From 7eb62fb5aa441bdb7e3519a903fb9eaa106b4e8b Mon Sep 17 00:00:00 2001 From: Didier Raboud Date: Fri, 18 Oct 2019 14:12:32 +0200 Subject: Import planetblupi_1.14.2-1.debian.tar.xz [dgit import tarball planetblupi 1.14.2-1 planetblupi_1.14.2-1.debian.tar.xz] --- .git-dpm | 8 +++ changelog | 158 +++++++++++++++++++++++++++++++++++++++++ control | 80 +++++++++++++++++++++ copyright | 54 ++++++++++++++ gbp.conf | 5 ++ planetblupi-common.install | 4 ++ planetblupi-music-midi.install | 1 + planetblupi-music-ogg.install | 1 + planetblupi.install | 4 ++ planetblupi.manpages | 1 + rules | 22 ++++++ source/format | 1 + upstream/metadata | 1 + watch | 2 + 14 files changed, 342 insertions(+) create mode 100644 .git-dpm create mode 100644 changelog create mode 100644 control create mode 100644 copyright create mode 100644 gbp.conf create mode 100644 planetblupi-common.install create mode 100644 planetblupi-music-midi.install create mode 100644 planetblupi-music-ogg.install create mode 100644 planetblupi.install create mode 100644 planetblupi.manpages create mode 100755 rules create mode 100644 source/format create mode 100644 upstream/metadata create mode 100644 watch diff --git a/.git-dpm b/.git-dpm new file mode 100644 index 0000000..4dae245 --- /dev/null +++ b/.git-dpm @@ -0,0 +1,8 @@ +# see git-dpm(1) from git-dpm package +a8c7c83494c86457091dc1b1ac8b1aa5b7d03a9c +a8c7c83494c86457091dc1b1ac8b1aa5b7d03a9c +a8c7c83494c86457091dc1b1ac8b1aa5b7d03a9c +a8c7c83494c86457091dc1b1ac8b1aa5b7d03a9c +planetblupi_1.14.0.orig.tar.xz +3f6aa1a72ab68de742fda69c064f98d64bb0c7cc +85884044 diff --git a/changelog b/changelog new file mode 100644 index 0000000..8d5b7c3 --- /dev/null +++ b/changelog @@ -0,0 +1,158 @@ +planetblupi (1.14.2-1) unstable; urgency=medium + + * New 1.14.2 upstream release + * Bump S-V to 4.4.1 without changes needed + * Set upstream metadata fields: Repository. + + -- Didier Raboud Fri, 18 Oct 2019 14:12:32 +0200 + +planetblupi (1.14.1-2) unstable; urgency=medium + + * Move to unstable + * Bump S-V to 4.4 without changes needed + * Bump debhelper compat to 12 + * Cherry-pick two fixes from upstream: + - Fix bad translation + - Do not play the win sound while the win video is playing + + -- Didier Raboud Fri, 20 Sep 2019 16:49:26 +0200 + +planetblupi (1.14.1-1) experimental; urgency=medium + + * New 1.14.1 upstream release + + -- Didier Raboud Wed, 13 Mar 2019 21:53:25 +0100 + +planetblupi (1.14.0-1) experimental; urgency=low + + * New 1.14.0 upstream release + + -- Didier Raboud Sun, 24 Feb 2019 15:27:22 +0100 + +planetblupi (1.13.2-3) unstable; urgency=medium + + * Generate and install the manpage: + - Patch to move it to section 6 (games) + - Add 'ronn' as Build-Dependency + + -- Didier Raboud Wed, 24 Oct 2018 08:45:19 +0200 + +planetblupi (1.13.2-2) unstable; urgency=medium + + * Upload to unstable + + -- Didier Raboud Mon, 17 Sep 2018 10:16:56 +0200 + +planetblupi (1.13.2-1) experimental; urgency=medium + + * New 1.13.2 release + * Bump S-V to 4.2.1 without changes needed + + -- Didier Raboud Mon, 03 Sep 2018 12:06:00 +0200 + +planetblupi (1.12.5-2) experimental; urgency=low + + * Adapt to libsdl-kitchensink's new API: + - Bump libsdl-kitchensink-dev B-D to >= 1 + - Backport two patches from upstream: + + Add SDL2 directory as include dir for SDL_kitchensink (Kit) + + Adapt movie impl. for SDL_kitchensink1 API + + -- Didier Raboud Fri, 06 Jul 2018 14:49:09 +0200 + +planetblupi (1.12.5-1) unstable; urgency=medium + + * New 1.12.5 release + + [ Reiner Herrmann ] + * Use fixed serial number to build ogg files reproducibly + * Point Vcs-* fields to salsa + * Bump Standards-Version to 4.1.4; no changes required + * Add watch file + + [ Didier Raboud ] + * d/copyright update + + -- Didier Raboud Fri, 08 Jun 2018 10:50:35 +0200 + +planetblupi (1.12.4-1) unstable; urgency=medium + + * New 1.12.4 release + + -- Didier Raboud Thu, 15 Mar 2018 08:49:52 +0100 + +planetblupi (1.12.2-1) unstable; urgency=medium + + * New 1.12.2 upstream release + - Drop the patches from upstream + + -- Didier Raboud Tue, 06 Feb 2018 20:41:19 +0100 + +planetblupi (1.12.1-22-g13a7e27-3) unstable; urgency=medium + + * Cherry-pick two upstream fixes to only allow music format choices + amongst those available + + -- Didier Raboud Fri, 02 Feb 2018 19:13:04 +0100 + +planetblupi (1.12.1-22-g13a7e27-2) unstable; urgency=medium + + * Add missing Replaces/Breaks in the two new packages + * Pipe timidity to sox for encoding to ogg + * Bump S-V to 4.1.3 without changes needed + + -- Didier Raboud Mon, 01 Jan 2018 10:41:23 +0100 + +planetblupi (1.12.1-22-g13a7e27-1) unstable; urgency=medium + + * New pre-1.12.2 snapshot; MIDI files are restored, no release yet + + * During build, convert the .mid's to .ogg's using timidity and + timgm6mb-soundfont + * Split data package in -music-mid and -music-ogg alternatives + + -- Didier Raboud Sun, 31 Dec 2017 14:41:26 +0100 + +planetblupi (1.12.0-16-g222113a-1) unstable; urgency=medium + + * New pre-1.12.1 snapshot; just before the MIDI-to-Ogg conversion + + -- Didier Raboud Fri, 08 Dec 2017 09:54:17 +0100 + +planetblupi (1.12.0-1) unstable; urgency=medium + + * New 1.12.0 upstream release + - Remove all patches which were from upstream + - Use @PB_ICON@ to link to the icon from the desktop file + * Set R³ to no + + -- Didier Raboud Thu, 02 Nov 2017 20:16:47 +0100 + +planetblupi (1.11.0-3) unstable; urgency=medium + + * Patches: + - Install a .desktop file: backport and enhance + - Make the CURL dependency optional: backport the enhancements + - Use GNUInstallDirs instead of patching the BINDIR: patch update + - Replace a char by Sint8: backport. Should fix the FTBFS'es + + -- Didier Raboud Wed, 25 Oct 2017 09:11:15 +0200 + +planetblupi (1.11.0-2) unstable; urgency=medium + + * Backport two patch series from upstream: + - Build a desktop file + - Make the CURL dependency optional, through the PB_HTTP_VERSION_CHECK + CMake option (refresh the previous attempt) + + * Use non-HTTPS homepage, the HTTPS version doesn't work + * Install the desktop file + * Add debian/gbp.conf + + -- Didier Raboud Sun, 22 Oct 2017 11:54:10 +0200 + +planetblupi (1.11.0-1) unstable; urgency=low + + * Initial release. (Closes: #879214) + + -- Didier Raboud Fri, 20 Oct 2017 16:57:03 +0200 diff --git a/control b/control new file mode 100644 index 0000000..4dc111a --- /dev/null +++ b/control @@ -0,0 +1,80 @@ +Source: planetblupi +Section: games +Priority: optional +Maintainer: Debian Games Team +Uploaders: Didier Raboud +Build-Depends: + debhelper-compat (= 12), + cmake, + pkg-config, + libsdl2-dev, + libsdl2-image-dev, + libsdl2-mixer-dev, + libsdl-kitchensink-dev (>= 1), + argagg-dev, + ronn, +Build-Depends-Indep: + timidity, + vorbis-tools, + timgm6mb-soundfont, +Standards-Version: 4.4.1 +Rules-Requires-Root: no +Homepage: http://blupi.org +Vcs-Git: https://salsa.debian.org/games-team/planetblupi.git +Vcs-Browser: https://salsa.debian.org/games-team/planetblupi + +Package: planetblupi +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, + planetblupi-common (>= ${source:Version}), + planetblupi-music-ogg (>= ${source:Version}) | planetblupi-music-midi (>= ${source:Version}), +Description: Planet Blupi - A delirious spell-binding game + Planet Blupi is a strategy and adventure game. It subtly blends action with + thought-provoking challenges. Behind the quiet and gentle facade, you'll enjoy + a fascinating diversion full of surprises. + +Package: planetblupi-common +Architecture: all +Multi-Arch: foreign +Depends: ${misc:Depends} +Enhances: planetblupi +Recommends: + planetblupi (>= ${source:Version}) +Description: Planet Blupi - A delirious spell-binding game - data + Planet Blupi is a strategy and adventure game. It subtly blends action with + thought-provoking challenges. Behind the quiet and gentle facade, you'll enjoy + a fascinating diversion full of surprises. + . + This package contains the architecture-independent game data. + +Package: planetblupi-music-ogg +Architecture: all +Multi-Arch: foreign +Depends: ${misc:Depends} +Enhances: planetblupi +Recommends: planetblupi (>= ${source:Version}) +Replaces: planetblupi-common (<< 1.12.1-22-g13a7e27-1) +Breaks: planetblupi-common (<< 1.12.1-22-g13a7e27-1) +Description: Planet Blupi - A delirious spell-binding game - Ogg music + Planet Blupi is a strategy and adventure game. It subtly blends action with + thought-provoking challenges. Behind the quiet and gentle facade, you'll enjoy + a fascinating diversion full of surprises. + . + This package contains the heavyweight OGG music. + +Package: planetblupi-music-midi +Architecture: all +Multi-Arch: foreign +Depends: ${misc:Depends}, + fluidr3mono-gm-soundfont | timgm6mb-soundfont | fluid-soundfont-gm, +# ^ these are libfluidsynth's suggests +Enhances: planetblupi +Recommends: planetblupi (>= ${source:Version}) +Replaces: planetblupi-common (<< 1.12.1-22-g13a7e27-1) +Breaks: planetblupi-common (<< 1.12.1-22-g13a7e27-1) +Description: Planet Blupi - A delirious spell-binding game - MIDI music + Planet Blupi is a strategy and adventure game. It subtly blends action with + thought-provoking challenges. Behind the quiet and gentle facade, you'll enjoy + a fascinating diversion full of surprises. + . + This package contains the lightweight MIDI music diff --git a/copyright b/copyright new file mode 100644 index 0000000..2d38a2f --- /dev/null +++ b/copyright @@ -0,0 +1,54 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: Planet Blupi +Upstream-Contact: Mathieu Schroeter +Source: https://github.com/blupi-games/planetblupi/ + +Files: * +Copyright: 2017,2018, Mathieu Schroeter + 1997, Daniel Roux, EPSITEC SA & Denis Dumoulin +License: GPL-3+ + +Files: debian/* +Copyright: 2017-2018, Didier Raboud +License: GPL-3+ + +Files: src/json/* +Copyright: 2013-2017, Niels Lohmann . +License: Expat + +License: Expat + The MIT 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. + +License: GPL-3+ + 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; version 3 dated June, 2007, or (at + your option) any later version. + . + On Debian systems, the complete text of version 3 of the GNU General + Public License can be found in '/usr/share/common-licenses/GPL-3' diff --git a/gbp.conf b/gbp.conf new file mode 100644 index 0000000..b0087de --- /dev/null +++ b/gbp.conf @@ -0,0 +1,5 @@ +[DEFAULT] +upstream-branch = upstream/latest +debian-branch = debian/master +[dch] +meta = true diff --git a/planetblupi-common.install b/planetblupi-common.install new file mode 100644 index 0000000..feb1ee5 --- /dev/null +++ b/planetblupi-common.install @@ -0,0 +1,4 @@ +usr/share/planetblupi/data/ +usr/share/planetblupi/image/ +usr/share/planetblupi/movie/ +usr/share/planetblupi/sound/ diff --git a/planetblupi-music-midi.install b/planetblupi-music-midi.install new file mode 100644 index 0000000..ec85ac4 --- /dev/null +++ b/planetblupi-music-midi.install @@ -0,0 +1 @@ +/usr/share/planetblupi/music/*.mid diff --git a/planetblupi-music-ogg.install b/planetblupi-music-ogg.install new file mode 100644 index 0000000..20c0d6e --- /dev/null +++ b/planetblupi-music-ogg.install @@ -0,0 +1 @@ +/usr/share/planetblupi/music/*.ogg diff --git a/planetblupi.install b/planetblupi.install new file mode 100644 index 0000000..915d9fa --- /dev/null +++ b/planetblupi.install @@ -0,0 +1,4 @@ +usr/games/planetblupi +usr/share/applications/planetblupi.desktop +usr/share/icons/hicolor/ +usr/share/locale/ diff --git a/planetblupi.manpages b/planetblupi.manpages new file mode 100644 index 0000000..2ae0a79 --- /dev/null +++ b/planetblupi.manpages @@ -0,0 +1 @@ +debian/tmp/usr/share/man/man6/planetblupi.6.gz diff --git a/rules b/rules new file mode 100755 index 0000000..d5875b8 --- /dev/null +++ b/rules @@ -0,0 +1,22 @@ +#!/usr/bin/make -f + +%: + dh $@ + +override_dh_auto_configure: + dh_auto_configure -- -DCMAKE_INSTALL_BINDIR=games + +midfiles := $(wildcard resources/music/music*.mid) +oggfiles := $(midfiles:.mid=.ogg) + +override_dh_clean-indep: + dh_clean -i + # These are shipped in the source archive, let's rebuild them + rm -f $(oggfiles) + +override_dh_auto_build-indep: $(oggfiles) + dh_auto_build -i + +resources/music/music%.ogg: resources/music/music%.mid + # Encode to ogg with "Quality=0" ~ 64 kB + timidity -c /etc/timidity/timgm6mb.cfg -Ow $< -o - | oggenc -Q -q0 --serial 1 -o $@ - diff --git a/source/format b/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/upstream/metadata b/upstream/metadata new file mode 100644 index 0000000..d73e564 --- /dev/null +++ b/upstream/metadata @@ -0,0 +1 @@ +Repository: https://github.com/blupi-games/planetblupi diff --git a/watch b/watch new file mode 100644 index 0000000..f8a0db7 --- /dev/null +++ b/watch @@ -0,0 +1,2 @@ +version=4 +https://github.com/blupi-games/planetblupi/releases .*/v?@ANY_VERSION@@ARCHIVE_EXT@ -- cgit v1.2.3 From 8859f7c7cbd584697638489336e432d82b93f4a9 Mon Sep 17 00:00:00 2001 From: Didier Raboud Date: Fri, 18 Oct 2019 14:12:32 +0200 Subject: Import planetblupi_1.14.2.orig.tar.gz [dgit import orig planetblupi_1.14.2.orig.tar.gz] --- .editorconfig | 9 + .gitattributes | 1 + .gitignore | 5 + .gitmodules | 0 CMakeLists.txt | 426 + COPYING | 29 + LICENSE | 696 ++ LICENSE.all | 3669 ++++++ README.md | 15 + README.translators.md | 81 + README.voices.md | 38 + blupi.png | Bin 0 -> 73786 bytes cmake/FindArgagg.cmake | 37 + cmake/FindIconv.cmake | 49 + cmake/FindSDLKitchensink.cmake | 58 + cmake/LinuxAppImageBuild.cmake | 154 + cmake/Ronn2Man.cmake | 59 + planetblupi.6.ronn | 211 + resources/darwin/Info.plist.in | 16 + resources/darwin/Planet Blupi | 2 + resources/darwin/background.png | Bin 0 -> 48279 bytes resources/darwin/background.svg | 323 + resources/darwin/background.tiff | Bin 0 -> 269820 bytes resources/darwin/background@2x.png | Bin 0 -> 186444 bytes resources/darwin/dmgsetup.scpt | 57 + resources/darwin/icon.icns | Bin 0 -> 54302 bytes resources/data/config.json | 5 + resources/data/de/stories.blp | 1010 ++ resources/data/demo000.blp | Bin 0 -> 7922 bytes resources/data/demo001.blp | Bin 0 -> 9170 bytes resources/data/demo002.blp | Bin 0 -> 7506 bytes resources/data/demo003.blp | Bin 0 -> 13426 bytes resources/data/en/stories.blp | 1118 ++ resources/data/fr/stories.blp | 1180 ++ resources/data/he/stories.blp | 1113 ++ resources/data/info.blp | Bin 0 -> 230 bytes resources/data/it/stories.blp | 1116 ++ resources/data/pl/stories.blp | 1110 ++ resources/data/pt/stories.blp | 1144 ++ resources/data/tr/stories.blp | 1096 ++ resources/data/user000.blp | Bin 0 -> 254436 bytes resources/data/user001.blp | Bin 0 -> 254036 bytes resources/data/user002.blp | Bin 0 -> 224036 bytes resources/data/user003.blp | Bin 0 -> 254436 bytes resources/data/user004.blp | Bin 0 -> 254436 bytes resources/data/user005.blp | Bin 0 -> 254436 bytes resources/data/user006.blp | Bin 0 -> 224036 bytes resources/data/user007.blp | Bin 0 -> 254436 bytes resources/data/user008.blp | Bin 0 -> 224036 bytes resources/data/user009.blp | Bin 0 -> 254436 bytes resources/data/world000.blp | Bin 0 -> 254436 bytes resources/data/world001.blp | Bin 0 -> 254436 bytes resources/data/world002.blp | Bin 0 -> 254436 bytes resources/data/world003.blp | Bin 0 -> 254436 bytes resources/data/world004.blp | Bin 0 -> 254436 bytes resources/data/world005.blp | Bin 0 -> 254036 bytes resources/data/world100.blp | Bin 0 -> 254436 bytes resources/data/world101.blp | Bin 0 -> 254436 bytes resources/data/world102.blp | Bin 0 -> 254436 bytes resources/data/world103.blp | Bin 0 -> 254436 bytes resources/data/world104.blp | Bin 0 -> 254436 bytes resources/data/world105.blp | Bin 0 -> 254436 bytes resources/data/world106.blp | Bin 0 -> 254436 bytes resources/data/world107.blp | Bin 0 -> 254436 bytes resources/data/world108.blp | Bin 0 -> 254436 bytes resources/data/world109.blp | Bin 0 -> 254436 bytes resources/data/world110.blp | Bin 0 -> 254436 bytes resources/data/world111.blp | Bin 0 -> 254436 bytes resources/data/world112.blp | Bin 0 -> 254436 bytes resources/data/world113.blp | Bin 0 -> 254436 bytes resources/data/world114.blp | Bin 0 -> 254436 bytes resources/data/world115.blp | Bin 0 -> 254436 bytes resources/data/world116.blp | Bin 0 -> 254436 bytes resources/data/world117.blp | Bin 0 -> 254436 bytes resources/data/world118.blp | Bin 0 -> 254436 bytes resources/data/world119.blp | Bin 0 -> 254436 bytes resources/data/world120.blp | Bin 0 -> 254436 bytes resources/data/world121.blp | Bin 0 -> 254436 bytes resources/data/world122.blp | Bin 0 -> 254436 bytes resources/data/world123.blp | Bin 0 -> 254436 bytes resources/data/world124.blp | Bin 0 -> 254436 bytes resources/data/world125.blp | Bin 0 -> 254436 bytes resources/data/world126.blp | Bin 0 -> 254436 bytes resources/data/world127.blp | Bin 0 -> 254436 bytes resources/data/world128.blp | Bin 0 -> 254436 bytes resources/data/world129.blp | Bin 0 -> 254436 bytes resources/data/world130.dev.blp | Bin 0 -> 254436 bytes resources/data/world131.dev.blp | Bin 0 -> 254036 bytes resources/data/world132.dev.blp | Bin 0 -> 224036 bytes resources/data/world133.dev.blp | Bin 0 -> 224036 bytes resources/data/world134.dev.blp | Bin 0 -> 224036 bytes resources/data/world135.dev.blp | Bin 0 -> 224036 bytes resources/data/world136.dev.blp | Bin 0 -> 224036 bytes resources/data/world137.dev.blp | Bin 0 -> 224036 bytes resources/data/world139.dev.blp | Bin 0 -> 224036 bytes resources/data/world140.dev.blp | Bin 0 -> 224036 bytes resources/data/world141.dev.blp | Bin 0 -> 224036 bytes resources/data/world142.dev.blp | Bin 0 -> 224036 bytes resources/data/world148.dev.blp | Bin 0 -> 254436 bytes resources/data/world150.blp | Bin 0 -> 254436 bytes resources/data/world151.blp | Bin 0 -> 254436 bytes resources/data/world152.blp | Bin 0 -> 254436 bytes resources/data/world153.blp | Bin 0 -> 254436 bytes resources/data/world200.blp | Bin 0 -> 254436 bytes resources/data/world201.blp | Bin 0 -> 224036 bytes resources/data/world202.blp | Bin 0 -> 224036 bytes resources/data/world203.blp | Bin 0 -> 254036 bytes resources/data/world204.blp | Bin 0 -> 254436 bytes resources/data/world205.blp | Bin 0 -> 254436 bytes resources/data/world206.blp | Bin 0 -> 254436 bytes resources/data/world207.blp | Bin 0 -> 254436 bytes resources/data/world208.blp | Bin 0 -> 254436 bytes resources/data/world209.blp | Bin 0 -> 254436 bytes resources/data/world210.blp | Bin 0 -> 254436 bytes resources/data/world211.blp | Bin 0 -> 254436 bytes resources/data/world212.blp | Bin 0 -> 254436 bytes resources/data/world213.blp | Bin 0 -> 254436 bytes resources/data/world214.blp | Bin 0 -> 254436 bytes resources/data/world215.blp | Bin 0 -> 254436 bytes resources/icon/blupi.icns | Bin 0 -> 54302 bytes resources/icon/blupi.ico | Bin 0 -> 33988 bytes resources/icon/blupi.iconset/icon_128x128.png | Bin 0 -> 615 bytes resources/icon/blupi.iconset/icon_128x128@2x.png | Bin 0 -> 803 bytes resources/icon/blupi.iconset/icon_16x16.png | Bin 0 -> 246 bytes resources/icon/blupi.iconset/icon_16x16@2x.png | Bin 0 -> 261 bytes resources/icon/blupi.iconset/icon_256x256.png | Bin 0 -> 803 bytes resources/icon/blupi.iconset/icon_256x256@2x.png | Bin 0 -> 1239 bytes resources/icon/blupi.iconset/icon_32x32.png | Bin 0 -> 374 bytes resources/icon/blupi.iconset/icon_32x32@2x.png | Bin 0 -> 426 bytes resources/icon/blupi.iconset/icon_512x512.png | Bin 0 -> 1239 bytes resources/icon/blupi.iconset/icon_512x512@2x.png | Bin 0 -> 2885 bytes resources/icon/hicolor/128x128/apps/blupi.png | Bin 0 -> 615 bytes resources/icon/hicolor/16x16/apps/blupi.png | Bin 0 -> 246 bytes resources/icon/hicolor/256x256/apps/blupi.png | Bin 0 -> 803 bytes resources/icon/hicolor/32x32/apps/blupi.png | Bin 0 -> 374 bytes resources/icon/hicolor/48x48/apps/blupi.png | Bin 0 -> 598 bytes resources/icon/hicolor/512x512/apps/blupi.png | Bin 0 -> 1239 bytes resources/icon/hicolor/64x64/apps/blupi.png | Bin 0 -> 702 bytes resources/icon/hicolor/scalable/apps/blupi.svg | 1399 +++ resources/image/back-book.png | Bin 0 -> 188843 bytes resources/image/back-build.png | Bin 0 -> 112249 bytes resources/image/back-bye.png | Bin 0 -> 117798 bytes resources/image/back-chest-r.png | Bin 0 -> 154164 bytes resources/image/back-chest-w.png | Bin 0 -> 165520 bytes resources/image/back-disco.png | Bin 0 -> 75824 bytes resources/image/back-lost.png | Bin 0 -> 91364 bytes resources/image/back-setup.png | Bin 0 -> 204513 bytes resources/image/back-stars.png | Bin 0 -> 8352 bytes resources/image/back-win.png | Bin 0 -> 118190 bytes resources/image/bignum.png | Bin 0 -> 5683 bytes resources/image/blupi.png | Bin 0 -> 736179 bytes resources/image/build.png | Bin 0 -> 105221 bytes resources/image/button.png | Bin 0 -> 82874 bytes resources/image/button00.png | Bin 0 -> 45187 bytes resources/image/bye.png | Bin 0 -> 95295 bytes resources/image/floor000.png | Bin 0 -> 201578 bytes resources/image/floor001.png | Bin 0 -> 224583 bytes resources/image/floor002.png | Bin 0 -> 259396 bytes resources/image/floor003.png | Bin 0 -> 228030 bytes resources/image/fog.png | Bin 0 -> 13050 bytes resources/image/he/init.png | Bin 0 -> 78084 bytes resources/image/help.png | Bin 0 -> 103102 bytes resources/image/hili.png | Bin 0 -> 502 bytes resources/image/history0.png | Bin 0 -> 103193 bytes resources/image/history1.png | Bin 0 -> 104566 bytes resources/image/info000.png | Bin 0 -> 74511 bytes resources/image/info001.png | Bin 0 -> 96903 bytes resources/image/info002.png | Bin 0 -> 98442 bytes resources/image/init.png | Bin 0 -> 76558 bytes resources/image/insert.png | Bin 0 -> 72122 bytes resources/image/intro1.png | Bin 0 -> 78847 bytes resources/image/jauge.png | Bin 0 -> 5084 bytes resources/image/last000.png | Bin 0 -> 76398 bytes resources/image/last001.png | Bin 0 -> 73872 bytes resources/image/last002.png | Bin 0 -> 104703 bytes resources/image/little.png | Bin 0 -> 2166 bytes resources/image/lost.png | Bin 0 -> 96193 bytes resources/image/mask1.png | Bin 0 -> 9731 bytes resources/image/mask2.png | Bin 0 -> 9876 bytes resources/image/movie.png | Bin 0 -> 330 bytes resources/image/music.png | Bin 0 -> 108426 bytes resources/image/obj-o000.png | Bin 0 -> 160300 bytes resources/image/obj-o001.png | Bin 0 -> 157320 bytes resources/image/obj-o002.png | Bin 0 -> 159075 bytes resources/image/obj-o003.png | Bin 0 -> 158206 bytes resources/image/obj000.png | Bin 0 -> 290298 bytes resources/image/obj001.png | Bin 0 -> 289408 bytes resources/image/obj002.png | Bin 0 -> 298734 bytes resources/image/obj003.png | Bin 0 -> 287383 bytes resources/image/play.png | Bin 0 -> 91431 bytes resources/image/read.png | Bin 0 -> 89844 bytes resources/image/region.png | Bin 0 -> 111425 bytes resources/image/setup00.png | Bin 0 -> 211042 bytes resources/image/setup01.png | Bin 0 -> 120980 bytes resources/image/stop000.png | Bin 0 -> 85637 bytes resources/image/stop001.png | Bin 0 -> 103836 bytes resources/image/stop002.png | Bin 0 -> 100783 bytes resources/image/term.png | Bin 0 -> 103497 bytes resources/image/text.png | Bin 0 -> 20741 bytes resources/image/win.png | Bin 0 -> 104703 bytes resources/image/write.png | Bin 0 -> 112221 bytes resources/linux/application.desktop.in | 10 + resources/linux/icon.svg | 1399 +++ resources/linux/planetblupi.appdata.xml | 21 + resources/movie/history2.mkv | Bin 0 -> 1839655 bytes resources/movie/play101.mkv | Bin 0 -> 1480636 bytes resources/movie/play103.mkv | Bin 0 -> 3186291 bytes resources/movie/play105.mkv | Bin 0 -> 2597514 bytes resources/movie/play107.mkv | Bin 0 -> 2504731 bytes resources/movie/play108.mkv | Bin 0 -> 2290521 bytes resources/movie/play110.mkv | Bin 0 -> 3369281 bytes resources/movie/play113.mkv | Bin 0 -> 1136541 bytes resources/movie/play116.mkv | Bin 0 -> 1996938 bytes resources/movie/play118.mkv | Bin 0 -> 2248908 bytes resources/movie/play119.mkv | Bin 0 -> 2794396 bytes resources/movie/play124.mkv | Bin 0 -> 2455165 bytes resources/movie/win005.mkv | Bin 0 -> 4441487 bytes resources/movie/win129.mkv | Bin 0 -> 3609401 bytes resources/music/music000.mid | Bin 0 -> 131400 bytes resources/music/music000.ogg | Bin 0 -> 12724663 bytes resources/music/music001.mid | Bin 0 -> 150115 bytes resources/music/music001.ogg | Bin 0 -> 12472314 bytes resources/music/music002.mid | Bin 0 -> 160403 bytes resources/music/music002.ogg | Bin 0 -> 12009171 bytes resources/music/music003.mid | Bin 0 -> 90444 bytes resources/music/music003.ogg | Bin 0 -> 9254922 bytes resources/music/music004.mid | Bin 0 -> 91458 bytes resources/music/music004.ogg | Bin 0 -> 4854247 bytes resources/music/music005.mid | Bin 0 -> 184644 bytes resources/music/music005.ogg | Bin 0 -> 4710862 bytes resources/music/music006.mid | Bin 0 -> 97149 bytes resources/music/music006.ogg | Bin 0 -> 4602855 bytes resources/music/music007.mid | Bin 0 -> 151127 bytes resources/music/music007.ogg | Bin 0 -> 4800059 bytes resources/music/music008.mid | Bin 0 -> 139355 bytes resources/music/music008.ogg | Bin 0 -> 4853980 bytes resources/music/music009.mid | Bin 0 -> 191817 bytes resources/music/music009.ogg | Bin 0 -> 4509020 bytes resources/nsis/NSIS.template.in | 1016 ++ resources/nsis/bootstrap.sh | 8 + resources/nsis/installer.bmp | Bin 0 -> 25818 bytes resources/nsis/installer.png | Bin 0 -> 152131 bytes resources/nsis/installer.svg | 268 + resources/po/de.po | 995 ++ resources/po/en_US.po | 910 ++ resources/po/fr.po | 1018 ++ resources/po/he.po | 975 ++ resources/po/it.po | 989 ++ resources/po/pl.po | 984 ++ resources/po/planetblupi.pot | 909 ++ resources/po/pt.po | 960 ++ resources/po/tr.po | 972 ++ resources/sound/de/sound002.wav | Bin 0 -> 12432 bytes resources/sound/de/sound003.wav | Bin 0 -> 26870 bytes resources/sound/de/sound004.wav | Bin 0 -> 18674 bytes resources/sound/de/sound005.wav | Bin 0 -> 13344 bytes resources/sound/de/sound006.wav | Bin 0 -> 31652 bytes resources/sound/de/sound007.wav | Bin 0 -> 39880 bytes resources/sound/de/sound008.wav | Bin 0 -> 25748 bytes resources/sound/de/sound009.wav | Bin 0 -> 21736 bytes resources/sound/de/sound010.wav | Bin 0 -> 35648 bytes resources/sound/de/sound014.wav | Bin 0 -> 6832 bytes resources/sound/de/sound017.wav | Bin 0 -> 33262 bytes resources/sound/de/sound018.wav | Bin 0 -> 38394 bytes resources/sound/de/sound019.wav | Bin 0 -> 45100 bytes resources/sound/de/sound027.wav | Bin 0 -> 14974 bytes resources/sound/de/sound033.wav | Bin 0 -> 55144 bytes resources/sound/de/sound037.wav | Bin 0 -> 20812 bytes resources/sound/de/sound056.wav | Bin 0 -> 35456 bytes resources/sound/de/sound057.wav | Bin 0 -> 28904 bytes resources/sound/de/sound058.wav | Bin 0 -> 21044 bytes resources/sound/de/sound059.wav | Bin 0 -> 25466 bytes resources/sound/de/sound060.wav | Bin 0 -> 22924 bytes resources/sound/de/sound061.wav | Bin 0 -> 24740 bytes resources/sound/de/sound062.wav | Bin 0 -> 30862 bytes resources/sound/de/sound063.wav | Bin 0 -> 29200 bytes resources/sound/de/sound064.wav | Bin 0 -> 15280 bytes resources/sound/de/sound065.wav | Bin 0 -> 33044 bytes resources/sound/de/sound066.wav | Bin 0 -> 47576 bytes resources/sound/de/sound067.wav | Bin 0 -> 38346 bytes resources/sound/de/sound068.wav | Bin 0 -> 22994 bytes resources/sound/de/sound069.wav | Bin 0 -> 21124 bytes resources/sound/de/sound070.wav | Bin 0 -> 33084 bytes resources/sound/de/sound071.wav | Bin 0 -> 25748 bytes resources/sound/de/sound072.wav | Bin 0 -> 21736 bytes resources/sound/de/sound073.wav | Bin 0 -> 35648 bytes resources/sound/en/sound000.wav | Bin 0 -> 1568 bytes resources/sound/en/sound001.wav | Bin 0 -> 11858 bytes resources/sound/en/sound002.wav | Bin 0 -> 15826 bytes resources/sound/en/sound003.wav | Bin 0 -> 10124 bytes resources/sound/en/sound004.wav | Bin 0 -> 21294 bytes resources/sound/en/sound005.wav | Bin 0 -> 32128 bytes resources/sound/en/sound006.wav | Bin 0 -> 21744 bytes resources/sound/en/sound007.wav | Bin 0 -> 24530 bytes resources/sound/en/sound008.wav | Bin 0 -> 26654 bytes resources/sound/en/sound009.wav | Bin 0 -> 20314 bytes resources/sound/en/sound010.wav | Bin 0 -> 18764 bytes resources/sound/en/sound011.wav | Bin 0 -> 1882 bytes resources/sound/en/sound012.wav | Bin 0 -> 3152 bytes resources/sound/en/sound013.wav | Bin 0 -> 13540 bytes resources/sound/en/sound014.wav | Bin 0 -> 5780 bytes resources/sound/en/sound015.wav | Bin 0 -> 17144 bytes resources/sound/en/sound016.wav | Bin 0 -> 52242 bytes resources/sound/en/sound017.wav | Bin 0 -> 34530 bytes resources/sound/en/sound018.wav | Bin 0 -> 90568 bytes resources/sound/en/sound019.wav | Bin 0 -> 41624 bytes resources/sound/en/sound020.wav | Bin 0 -> 7194 bytes resources/sound/en/sound021.wav | Bin 0 -> 3516 bytes resources/sound/en/sound022.wav | Bin 0 -> 20814 bytes resources/sound/en/sound023.wav | Bin 0 -> 12176 bytes resources/sound/en/sound024.wav | Bin 0 -> 18438 bytes resources/sound/en/sound025.wav | Bin 0 -> 5430 bytes resources/sound/en/sound026.wav | Bin 0 -> 3948 bytes resources/sound/en/sound027.wav | Bin 0 -> 26410 bytes resources/sound/en/sound028.wav | Bin 0 -> 47784 bytes resources/sound/en/sound029.wav | Bin 0 -> 5269 bytes resources/sound/en/sound030.wav | Bin 0 -> 91674 bytes resources/sound/en/sound031.wav | Bin 0 -> 14854 bytes resources/sound/en/sound032.wav | Bin 0 -> 3424 bytes resources/sound/en/sound033.wav | Bin 0 -> 75324 bytes resources/sound/en/sound034.wav | Bin 0 -> 79746 bytes resources/sound/en/sound035.wav | Bin 0 -> 15144 bytes resources/sound/en/sound036.wav | Bin 0 -> 12072 bytes resources/sound/en/sound037.wav | Bin 0 -> 45924 bytes resources/sound/en/sound038.wav | Bin 0 -> 15928 bytes resources/sound/en/sound039.wav | Bin 0 -> 45784 bytes resources/sound/en/sound040.wav | Bin 0 -> 652 bytes resources/sound/en/sound041.wav | Bin 0 -> 20430 bytes resources/sound/en/sound042.wav | Bin 0 -> 99118 bytes resources/sound/en/sound043.wav | Bin 0 -> 7212 bytes resources/sound/en/sound044.wav | Bin 0 -> 23076 bytes resources/sound/en/sound045.wav | Bin 0 -> 11264 bytes resources/sound/en/sound046.wav | Bin 0 -> 114346 bytes resources/sound/en/sound047.wav | Bin 0 -> 90860 bytes resources/sound/en/sound048.wav | Bin 0 -> 130026 bytes resources/sound/en/sound049.wav | Bin 0 -> 12258 bytes resources/sound/en/sound050.wav | Bin 0 -> 47620 bytes resources/sound/en/sound051.wav | Bin 0 -> 9054 bytes resources/sound/en/sound052.wav | Bin 0 -> 7004 bytes resources/sound/en/sound053.wav | Bin 0 -> 7004 bytes resources/sound/en/sound054.wav | Bin 0 -> 3398 bytes resources/sound/en/sound055.wav | Bin 0 -> 6752 bytes resources/sound/en/sound056.wav | Bin 0 -> 33218 bytes resources/sound/en/sound057.wav | Bin 0 -> 23560 bytes resources/sound/en/sound058.wav | Bin 0 -> 29830 bytes resources/sound/en/sound059.wav | Bin 0 -> 35732 bytes resources/sound/en/sound060.wav | Bin 0 -> 23324 bytes resources/sound/en/sound061.wav | Bin 0 -> 28508 bytes resources/sound/en/sound062.wav | Bin 0 -> 23874 bytes resources/sound/en/sound063.wav | Bin 0 -> 46582 bytes resources/sound/en/sound064.wav | Bin 0 -> 28420 bytes resources/sound/en/sound065.wav | Bin 0 -> 27720 bytes resources/sound/en/sound066.wav | Bin 0 -> 35740 bytes resources/sound/en/sound067.wav | Bin 0 -> 40240 bytes resources/sound/en/sound068.wav | Bin 0 -> 29606 bytes resources/sound/en/sound069.wav | Bin 0 -> 20552 bytes resources/sound/en/sound070.wav | Bin 0 -> 17784 bytes resources/sound/en/sound071.wav | Bin 0 -> 24504 bytes resources/sound/en/sound072.wav | Bin 0 -> 25324 bytes resources/sound/en/sound073.wav | Bin 0 -> 22786 bytes resources/sound/en/sound074.wav | Bin 0 -> 4662 bytes resources/sound/en/sound075.wav | Bin 0 -> 7756 bytes resources/sound/en/sound076.wav | Bin 0 -> 3490 bytes resources/sound/en/sound077.wav | Bin 0 -> 3578 bytes resources/sound/en/sound078.wav | Bin 0 -> 8156 bytes resources/sound/en/sound079.wav | Bin 0 -> 8926 bytes resources/sound/en/sound080.wav | Bin 0 -> 77454 bytes resources/sound/en/sound081.wav | Bin 0 -> 21946 bytes resources/sound/en/sound082.wav | Bin 0 -> 18304 bytes resources/sound/en/sound083.wav | Bin 0 -> 147478 bytes resources/sound/en/sound084.wav | Bin 0 -> 125016 bytes resources/sound/en_US/sound002.wav | Bin 0 -> 17202 bytes resources/sound/en_US/sound003.wav | Bin 0 -> 16886 bytes resources/sound/en_US/sound004.wav | Bin 0 -> 32590 bytes resources/sound/en_US/sound005.wav | Bin 0 -> 19264 bytes resources/sound/en_US/sound006.wav | Bin 0 -> 23488 bytes resources/sound/en_US/sound007.wav | Bin 0 -> 25594 bytes resources/sound/en_US/sound008.wav | Bin 0 -> 26652 bytes resources/sound/en_US/sound009.wav | Bin 0 -> 23644 bytes resources/sound/en_US/sound010.wav | Bin 0 -> 19564 bytes resources/sound/en_US/sound014.wav | Bin 0 -> 14174 bytes resources/sound/en_US/sound017.wav | Bin 0 -> 74268 bytes resources/sound/en_US/sound018.wav | Bin 0 -> 81774 bytes resources/sound/en_US/sound019.wav | Bin 0 -> 33160 bytes resources/sound/en_US/sound027.wav | Bin 0 -> 29580 bytes resources/sound/en_US/sound033.wav | Bin 0 -> 60040 bytes resources/sound/en_US/sound037.wav | Bin 0 -> 36758 bytes resources/sound/en_US/sound056.wav | Bin 0 -> 41012 bytes resources/sound/en_US/sound057.wav | Bin 0 -> 26730 bytes resources/sound/en_US/sound058.wav | Bin 0 -> 26844 bytes resources/sound/en_US/sound059.wav | Bin 0 -> 40342 bytes resources/sound/en_US/sound060.wav | Bin 0 -> 26450 bytes resources/sound/en_US/sound061.wav | Bin 0 -> 29188 bytes resources/sound/en_US/sound062.wav | Bin 0 -> 28816 bytes resources/sound/en_US/sound063.wav | Bin 0 -> 25324 bytes resources/sound/en_US/sound064.wav | Bin 0 -> 27222 bytes resources/sound/en_US/sound065.wav | Bin 0 -> 29314 bytes resources/sound/en_US/sound066.wav | Bin 0 -> 36882 bytes resources/sound/en_US/sound067.wav | Bin 0 -> 47198 bytes resources/sound/en_US/sound068.wav | Bin 0 -> 30228 bytes resources/sound/en_US/sound069.wav | Bin 0 -> 24682 bytes resources/sound/en_US/sound070.wav | Bin 0 -> 13600 bytes resources/sound/en_US/sound071.wav | Bin 0 -> 28448 bytes resources/sound/en_US/sound072.wav | Bin 0 -> 30050 bytes resources/sound/en_US/sound073.wav | Bin 0 -> 37904 bytes resources/sound/fr/sound002.wav | Bin 0 -> 15304 bytes resources/sound/fr/sound003.wav | Bin 0 -> 21616 bytes resources/sound/fr/sound004.wav | Bin 0 -> 20566 bytes resources/sound/fr/sound005.wav | Bin 0 -> 24340 bytes resources/sound/fr/sound006.wav | Bin 0 -> 21542 bytes resources/sound/fr/sound007.wav | Bin 0 -> 26336 bytes resources/sound/fr/sound008.wav | Bin 0 -> 18440 bytes resources/sound/fr/sound009.wav | Bin 0 -> 18322 bytes resources/sound/fr/sound010.wav | Bin 0 -> 19392 bytes resources/sound/fr/sound014.wav | Bin 0 -> 6832 bytes resources/sound/fr/sound017.wav | Bin 0 -> 28934 bytes resources/sound/fr/sound018.wav | Bin 0 -> 34044 bytes resources/sound/fr/sound019.wav | Bin 0 -> 23936 bytes resources/sound/fr/sound027.wav | Bin 0 -> 11220 bytes resources/sound/fr/sound033.wav | Bin 0 -> 26948 bytes resources/sound/fr/sound037.wav | Bin 0 -> 9158 bytes resources/sound/fr/sound056.wav | Bin 0 -> 31050 bytes resources/sound/fr/sound057.wav | Bin 0 -> 28382 bytes resources/sound/fr/sound058.wav | Bin 0 -> 30644 bytes resources/sound/fr/sound059.wav | Bin 0 -> 36476 bytes resources/sound/fr/sound060.wav | Bin 0 -> 26642 bytes resources/sound/fr/sound061.wav | Bin 0 -> 21962 bytes resources/sound/fr/sound062.wav | Bin 0 -> 10684 bytes resources/sound/fr/sound063.wav | Bin 0 -> 16214 bytes resources/sound/fr/sound064.wav | Bin 0 -> 15052 bytes resources/sound/fr/sound065.wav | Bin 0 -> 35444 bytes resources/sound/fr/sound066.wav | Bin 0 -> 40970 bytes resources/sound/fr/sound067.wav | Bin 0 -> 31050 bytes resources/sound/fr/sound068.wav | Bin 0 -> 31574 bytes resources/sound/fr/sound069.wav | Bin 0 -> 29166 bytes resources/sound/fr/sound070.wav | Bin 0 -> 23588 bytes resources/sound/fr/sound071.wav | Bin 0 -> 21920 bytes resources/sound/fr/sound072.wav | Bin 0 -> 24544 bytes resources/sound/fr/sound073.wav | Bin 0 -> 23732 bytes resources/sound/he/sound002.wav | Bin 0 -> 17004 bytes resources/sound/he/sound003.wav | Bin 0 -> 15020 bytes resources/sound/he/sound004.wav | Bin 0 -> 24094 bytes resources/sound/he/sound005.wav | Bin 0 -> 25810 bytes resources/sound/he/sound006.wav | Bin 0 -> 32812 bytes resources/sound/he/sound007.wav | Bin 0 -> 31532 bytes resources/sound/he/sound008.wav | Bin 0 -> 25838 bytes resources/sound/he/sound009.wav | Bin 0 -> 26348 bytes resources/sound/he/sound010.wav | Bin 0 -> 19564 bytes resources/sound/he/sound014.wav | Bin 0 -> 18732 bytes resources/sound/he/sound017.wav | Bin 0 -> 44332 bytes resources/sound/he/sound018.wav | Bin 0 -> 94766 bytes resources/sound/he/sound019.wav | Bin 0 -> 45422 bytes resources/sound/he/sound027.wav | Bin 0 -> 44398 bytes resources/sound/he/sound033.wav | Bin 0 -> 76462 bytes resources/sound/he/sound037.wav | Bin 0 -> 66670 bytes resources/sound/he/sound056.wav | Bin 0 -> 52782 bytes resources/sound/he/sound057.wav | Bin 0 -> 28716 bytes resources/sound/he/sound058.wav | Bin 0 -> 42358 bytes resources/sound/he/sound059.wav | Bin 0 -> 38548 bytes resources/sound/he/sound060.wav | Bin 0 -> 26284 bytes resources/sound/he/sound061.wav | Bin 0 -> 22508 bytes resources/sound/he/sound062.wav | Bin 0 -> 32236 bytes resources/sound/he/sound063.wav | Bin 0 -> 35886 bytes resources/sound/he/sound064.wav | Bin 0 -> 35948 bytes resources/sound/he/sound065.wav | Bin 0 -> 30766 bytes resources/sound/he/sound066.wav | Bin 0 -> 43886 bytes resources/sound/he/sound067.wav | Bin 0 -> 48046 bytes resources/sound/he/sound068.wav | Bin 0 -> 26924 bytes resources/sound/he/sound069.wav | Bin 0 -> 24620 bytes resources/sound/he/sound070.wav | Bin 0 -> 26626 bytes resources/sound/he/sound071.wav | Bin 0 -> 20972 bytes resources/sound/he/sound072.wav | Bin 0 -> 30636 bytes resources/sound/he/sound073.wav | Bin 0 -> 22892 bytes resources/sound/it/sound002.wav | Bin 0 -> 10796 bytes resources/sound/it/sound003.wav | Bin 0 -> 16428 bytes resources/sound/it/sound004.wav | Bin 0 -> 13356 bytes resources/sound/it/sound005.wav | Bin 0 -> 14892 bytes resources/sound/it/sound006.wav | Bin 0 -> 21548 bytes resources/sound/it/sound007.wav | Bin 0 -> 25132 bytes resources/sound/it/sound008.wav | Bin 0 -> 22060 bytes resources/sound/it/sound009.wav | Bin 0 -> 17964 bytes resources/sound/it/sound010.wav | Bin 0 -> 15916 bytes resources/sound/it/sound014.wav | Bin 0 -> 19116 bytes resources/sound/it/sound017.wav | Bin 0 -> 34348 bytes resources/sound/it/sound018.wav | Bin 0 -> 57216 bytes resources/sound/it/sound019.wav | Bin 0 -> 21804 bytes resources/sound/it/sound027.wav | Bin 0 -> 22188 bytes resources/sound/it/sound033.wav | Bin 0 -> 41004 bytes resources/sound/it/sound037.wav | Bin 0 -> 24108 bytes resources/sound/it/sound056.wav | Bin 0 -> 28972 bytes resources/sound/it/sound057.wav | Bin 0 -> 25644 bytes resources/sound/it/sound058.wav | Bin 0 -> 13868 bytes resources/sound/it/sound059.wav | Bin 0 -> 25388 bytes resources/sound/it/sound060.wav | Bin 0 -> 32812 bytes resources/sound/it/sound061.wav | Bin 0 -> 17452 bytes resources/sound/it/sound062.wav | Bin 0 -> 32072 bytes resources/sound/it/sound063.wav | Bin 0 -> 26156 bytes resources/sound/it/sound064.wav | Bin 0 -> 35372 bytes resources/sound/it/sound065.wav | Bin 0 -> 22060 bytes resources/sound/it/sound066.wav | Bin 0 -> 33836 bytes resources/sound/it/sound067.wav | Bin 0 -> 32812 bytes resources/sound/it/sound068.wav | Bin 0 -> 28455 bytes resources/sound/it/sound069.wav | Bin 0 -> 16582 bytes resources/sound/it/sound070.wav | Bin 0 -> 29996 bytes resources/sound/it/sound071.wav | Bin 0 -> 12844 bytes resources/sound/it/sound072.wav | Bin 0 -> 22828 bytes resources/sound/it/sound073.wav | Bin 0 -> 25132 bytes resources/win32/planetblupi.rc.in | 25 + src/.clang-format | 97 + src/action.cxx | 2931 +++++ src/action.h | 31 + src/blupi.cxx | 1158 ++ src/blupi.h | 118 + src/button.cxx | 453 + src/button.h | 89 + src/config.h.in | 25 + src/decblupi.cxx | 4728 ++++++++ src/decgoal.cxx | 3569 ++++++ src/decgoal.h | 81 + src/decio.cxx | 525 + src/decmap.cxx | 595 + src/decmove.cxx | 1446 +++ src/decmove.h | 26 + src/decor.cxx | 3509 ++++++ src/decor.h | 575 + src/decstat.cxx | 1061 ++ src/def.h | 638 + src/display.cxx | 97 + src/display.h | 73 + src/event.cxx | 6422 ++++++++++ src/event.h | 284 + src/fifo.cxx | 91 + src/fifo.h | 48 + src/fix.cxx | 951 ++ src/fog.cxx | 156 + src/gettext.h | 24 + src/json/json.hpp | 13003 +++++++++++++++++++++ src/menu.cxx | 516 + src/menu.h | 75 + src/misc.cxx | 213 + src/misc.h | 80 + src/movie.cxx | 348 + src/movie.h | 70 + src/obstacle.cxx | 3816 ++++++ src/path.cxx | 390 + src/pixmap.cxx | 1061 ++ src/pixmap.h | 139 + src/platform.h | 37 + src/platform/platform_js.cxx | 58 + src/platform/platform_sdl.cxx | 57 + src/progress.cxx | 145 + src/progress.h | 57 + src/sound.cxx | 446 + src/sound.h | 86 + src/text.cxx | 502 + src/text.h | 44 + 556 files changed, 78629 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 CMakeLists.txt create mode 100644 COPYING create mode 100644 LICENSE create mode 100644 LICENSE.all create mode 100644 README.md create mode 100644 README.translators.md create mode 100644 README.voices.md create mode 100644 blupi.png create mode 100644 cmake/FindArgagg.cmake create mode 100644 cmake/FindIconv.cmake create mode 100644 cmake/FindSDLKitchensink.cmake create mode 100644 cmake/LinuxAppImageBuild.cmake create mode 100644 cmake/Ronn2Man.cmake create mode 100644 planetblupi.6.ronn create mode 100644 resources/darwin/Info.plist.in create mode 100755 resources/darwin/Planet Blupi create mode 100644 resources/darwin/background.png create mode 100644 resources/darwin/background.svg create mode 100644 resources/darwin/background.tiff create mode 100644 resources/darwin/background@2x.png create mode 100644 resources/darwin/dmgsetup.scpt create mode 100644 resources/darwin/icon.icns create mode 100644 resources/data/config.json create mode 100644 resources/data/de/stories.blp create mode 100644 resources/data/demo000.blp create mode 100644 resources/data/demo001.blp create mode 100644 resources/data/demo002.blp create mode 100644 resources/data/demo003.blp create mode 100644 resources/data/en/stories.blp create mode 100644 resources/data/fr/stories.blp create mode 100644 resources/data/he/stories.blp create mode 100644 resources/data/info.blp create mode 100644 resources/data/it/stories.blp create mode 100644 resources/data/pl/stories.blp create mode 100644 resources/data/pt/stories.blp create mode 100644 resources/data/tr/stories.blp create mode 100644 resources/data/user000.blp create mode 100644 resources/data/user001.blp create mode 100644 resources/data/user002.blp create mode 100644 resources/data/user003.blp create mode 100644 resources/data/user004.blp create mode 100644 resources/data/user005.blp create mode 100644 resources/data/user006.blp create mode 100644 resources/data/user007.blp create mode 100644 resources/data/user008.blp create mode 100644 resources/data/user009.blp create mode 100644 resources/data/world000.blp create mode 100644 resources/data/world001.blp create mode 100644 resources/data/world002.blp create mode 100644 resources/data/world003.blp create mode 100644 resources/data/world004.blp create mode 100644 resources/data/world005.blp create mode 100644 resources/data/world100.blp create mode 100644 resources/data/world101.blp create mode 100644 resources/data/world102.blp create mode 100644 resources/data/world103.blp create mode 100644 resources/data/world104.blp create mode 100644 resources/data/world105.blp create mode 100644 resources/data/world106.blp create mode 100644 resources/data/world107.blp create mode 100644 resources/data/world108.blp create mode 100644 resources/data/world109.blp create mode 100644 resources/data/world110.blp create mode 100644 resources/data/world111.blp create mode 100644 resources/data/world112.blp create mode 100644 resources/data/world113.blp create mode 100644 resources/data/world114.blp create mode 100644 resources/data/world115.blp create mode 100644 resources/data/world116.blp create mode 100644 resources/data/world117.blp create mode 100644 resources/data/world118.blp create mode 100644 resources/data/world119.blp create mode 100644 resources/data/world120.blp create mode 100644 resources/data/world121.blp create mode 100644 resources/data/world122.blp create mode 100644 resources/data/world123.blp create mode 100644 resources/data/world124.blp create mode 100644 resources/data/world125.blp create mode 100644 resources/data/world126.blp create mode 100644 resources/data/world127.blp create mode 100644 resources/data/world128.blp create mode 100644 resources/data/world129.blp create mode 100644 resources/data/world130.dev.blp create mode 100644 resources/data/world131.dev.blp create mode 100644 resources/data/world132.dev.blp create mode 100644 resources/data/world133.dev.blp create mode 100644 resources/data/world134.dev.blp create mode 100644 resources/data/world135.dev.blp create mode 100644 resources/data/world136.dev.blp create mode 100644 resources/data/world137.dev.blp create mode 100644 resources/data/world139.dev.blp create mode 100644 resources/data/world140.dev.blp create mode 100644 resources/data/world141.dev.blp create mode 100644 resources/data/world142.dev.blp create mode 100644 resources/data/world148.dev.blp create mode 100644 resources/data/world150.blp create mode 100644 resources/data/world151.blp create mode 100644 resources/data/world152.blp create mode 100644 resources/data/world153.blp create mode 100755 resources/data/world200.blp create mode 100644 resources/data/world201.blp create mode 100644 resources/data/world202.blp create mode 100644 resources/data/world203.blp create mode 100644 resources/data/world204.blp create mode 100644 resources/data/world205.blp create mode 100644 resources/data/world206.blp create mode 100644 resources/data/world207.blp create mode 100644 resources/data/world208.blp create mode 100644 resources/data/world209.blp create mode 100644 resources/data/world210.blp create mode 100644 resources/data/world211.blp create mode 100644 resources/data/world212.blp create mode 100644 resources/data/world213.blp create mode 100644 resources/data/world214.blp create mode 100644 resources/data/world215.blp create mode 100644 resources/icon/blupi.icns create mode 100644 resources/icon/blupi.ico create mode 100644 resources/icon/blupi.iconset/icon_128x128.png create mode 100644 resources/icon/blupi.iconset/icon_128x128@2x.png create mode 100644 resources/icon/blupi.iconset/icon_16x16.png create mode 100644 resources/icon/blupi.iconset/icon_16x16@2x.png create mode 100644 resources/icon/blupi.iconset/icon_256x256.png create mode 100644 resources/icon/blupi.iconset/icon_256x256@2x.png create mode 100644 resources/icon/blupi.iconset/icon_32x32.png create mode 100644 resources/icon/blupi.iconset/icon_32x32@2x.png create mode 100644 resources/icon/blupi.iconset/icon_512x512.png create mode 100644 resources/icon/blupi.iconset/icon_512x512@2x.png create mode 100644 resources/icon/hicolor/128x128/apps/blupi.png create mode 100644 resources/icon/hicolor/16x16/apps/blupi.png create mode 100644 resources/icon/hicolor/256x256/apps/blupi.png create mode 100644 resources/icon/hicolor/32x32/apps/blupi.png create mode 100644 resources/icon/hicolor/48x48/apps/blupi.png create mode 100644 resources/icon/hicolor/512x512/apps/blupi.png create mode 100644 resources/icon/hicolor/64x64/apps/blupi.png create mode 100644 resources/icon/hicolor/scalable/apps/blupi.svg create mode 100644 resources/image/back-book.png create mode 100644 resources/image/back-build.png create mode 100644 resources/image/back-bye.png create mode 100644 resources/image/back-chest-r.png create mode 100644 resources/image/back-chest-w.png create mode 100644 resources/image/back-disco.png create mode 100644 resources/image/back-lost.png create mode 100644 resources/image/back-setup.png create mode 100644 resources/image/back-stars.png create mode 100644 resources/image/back-win.png create mode 100644 resources/image/bignum.png create mode 100644 resources/image/blupi.png create mode 100644 resources/image/build.png create mode 100644 resources/image/button.png create mode 100644 resources/image/button00.png create mode 100644 resources/image/bye.png create mode 100644 resources/image/floor000.png create mode 100644 resources/image/floor001.png create mode 100644 resources/image/floor002.png create mode 100644 resources/image/floor003.png create mode 100644 resources/image/fog.png create mode 100644 resources/image/he/init.png create mode 100644 resources/image/help.png create mode 100644 resources/image/hili.png create mode 100644 resources/image/history0.png create mode 100644 resources/image/history1.png create mode 100644 resources/image/info000.png create mode 100644 resources/image/info001.png create mode 100644 resources/image/info002.png create mode 100644 resources/image/init.png create mode 100644 resources/image/insert.png create mode 100644 resources/image/intro1.png create mode 100644 resources/image/jauge.png create mode 100644 resources/image/last000.png create mode 100644 resources/image/last001.png create mode 100644 resources/image/last002.png create mode 100644 resources/image/little.png create mode 100644 resources/image/lost.png create mode 100644 resources/image/mask1.png create mode 100644 resources/image/mask2.png create mode 100644 resources/image/movie.png create mode 100644 resources/image/music.png create mode 100644 resources/image/obj-o000.png create mode 100644 resources/image/obj-o001.png create mode 100644 resources/image/obj-o002.png create mode 100644 resources/image/obj-o003.png create mode 100644 resources/image/obj000.png create mode 100644 resources/image/obj001.png create mode 100644 resources/image/obj002.png create mode 100644 resources/image/obj003.png create mode 100644 resources/image/play.png create mode 100644 resources/image/read.png create mode 100644 resources/image/region.png create mode 100644 resources/image/setup00.png create mode 100644 resources/image/setup01.png create mode 100644 resources/image/stop000.png create mode 100644 resources/image/stop001.png create mode 100644 resources/image/stop002.png create mode 100644 resources/image/term.png create mode 100644 resources/image/text.png create mode 100644 resources/image/win.png create mode 100644 resources/image/write.png create mode 100644 resources/linux/application.desktop.in create mode 100644 resources/linux/icon.svg create mode 100644 resources/linux/planetblupi.appdata.xml create mode 100644 resources/movie/history2.mkv create mode 100644 resources/movie/play101.mkv create mode 100644 resources/movie/play103.mkv create mode 100644 resources/movie/play105.mkv create mode 100644 resources/movie/play107.mkv create mode 100644 resources/movie/play108.mkv create mode 100644 resources/movie/play110.mkv create mode 100644 resources/movie/play113.mkv create mode 100644 resources/movie/play116.mkv create mode 100644 resources/movie/play118.mkv create mode 100644 resources/movie/play119.mkv create mode 100644 resources/movie/play124.mkv create mode 100644 resources/movie/win005.mkv create mode 100644 resources/movie/win129.mkv create mode 100644 resources/music/music000.mid create mode 100644 resources/music/music000.ogg create mode 100644 resources/music/music001.mid create mode 100644 resources/music/music001.ogg create mode 100644 resources/music/music002.mid create mode 100644 resources/music/music002.ogg create mode 100644 resources/music/music003.mid create mode 100644 resources/music/music003.ogg create mode 100644 resources/music/music004.mid create mode 100644 resources/music/music004.ogg create mode 100644 resources/music/music005.mid create mode 100644 resources/music/music005.ogg create mode 100644 resources/music/music006.mid create mode 100644 resources/music/music006.ogg create mode 100644 resources/music/music007.mid create mode 100644 resources/music/music007.ogg create mode 100644 resources/music/music008.mid create mode 100644 resources/music/music008.ogg create mode 100644 resources/music/music009.mid create mode 100644 resources/music/music009.ogg create mode 100644 resources/nsis/NSIS.template.in create mode 100755 resources/nsis/bootstrap.sh create mode 100644 resources/nsis/installer.bmp create mode 100644 resources/nsis/installer.png create mode 100644 resources/nsis/installer.svg create mode 100644 resources/po/de.po create mode 100644 resources/po/en_US.po create mode 100644 resources/po/fr.po create mode 100644 resources/po/he.po create mode 100644 resources/po/it.po create mode 100644 resources/po/pl.po create mode 100644 resources/po/planetblupi.pot create mode 100644 resources/po/pt.po create mode 100644 resources/po/tr.po create mode 100644 resources/sound/de/sound002.wav create mode 100644 resources/sound/de/sound003.wav create mode 100644 resources/sound/de/sound004.wav create mode 100644 resources/sound/de/sound005.wav create mode 100644 resources/sound/de/sound006.wav create mode 100644 resources/sound/de/sound007.wav create mode 100644 resources/sound/de/sound008.wav create mode 100644 resources/sound/de/sound009.wav create mode 100644 resources/sound/de/sound010.wav create mode 100644 resources/sound/de/sound014.wav create mode 100644 resources/sound/de/sound017.wav create mode 100644 resources/sound/de/sound018.wav create mode 100644 resources/sound/de/sound019.wav create mode 100644 resources/sound/de/sound027.wav create mode 100644 resources/sound/de/sound033.wav create mode 100644 resources/sound/de/sound037.wav create mode 100644 resources/sound/de/sound056.wav create mode 100644 resources/sound/de/sound057.wav create mode 100644 resources/sound/de/sound058.wav create mode 100644 resources/sound/de/sound059.wav create mode 100644 resources/sound/de/sound060.wav create mode 100644 resources/sound/de/sound061.wav create mode 100644 resources/sound/de/sound062.wav create mode 100644 resources/sound/de/sound063.wav create mode 100644 resources/sound/de/sound064.wav create mode 100644 resources/sound/de/sound065.wav create mode 100644 resources/sound/de/sound066.wav create mode 100644 resources/sound/de/sound067.wav create mode 100644 resources/sound/de/sound068.wav create mode 100644 resources/sound/de/sound069.wav create mode 100644 resources/sound/de/sound070.wav create mode 100644 resources/sound/de/sound071.wav create mode 100644 resources/sound/de/sound072.wav create mode 100644 resources/sound/de/sound073.wav create mode 100644 resources/sound/en/sound000.wav create mode 100644 resources/sound/en/sound001.wav create mode 100644 resources/sound/en/sound002.wav create mode 100644 resources/sound/en/sound003.wav create mode 100644 resources/sound/en/sound004.wav create mode 100644 resources/sound/en/sound005.wav create mode 100644 resources/sound/en/sound006.wav create mode 100644 resources/sound/en/sound007.wav create mode 100644 resources/sound/en/sound008.wav create mode 100644 resources/sound/en/sound009.wav create mode 100644 resources/sound/en/sound010.wav create mode 100644 resources/sound/en/sound011.wav create mode 100644 resources/sound/en/sound012.wav create mode 100644 resources/sound/en/sound013.wav create mode 100644 resources/sound/en/sound014.wav create mode 100644 resources/sound/en/sound015.wav create mode 100644 resources/sound/en/sound016.wav create mode 100644 resources/sound/en/sound017.wav create mode 100644 resources/sound/en/sound018.wav create mode 100644 resources/sound/en/sound019.wav create mode 100644 resources/sound/en/sound020.wav create mode 100644 resources/sound/en/sound021.wav create mode 100644 resources/sound/en/sound022.wav create mode 100644 resources/sound/en/sound023.wav create mode 100644 resources/sound/en/sound024.wav create mode 100644 resources/sound/en/sound025.wav create mode 100644 resources/sound/en/sound026.wav create mode 100644 resources/sound/en/sound027.wav create mode 100644 resources/sound/en/sound028.wav create mode 100644 resources/sound/en/sound029.wav create mode 100644 resources/sound/en/sound030.wav create mode 100644 resources/sound/en/sound031.wav create mode 100644 resources/sound/en/sound032.wav create mode 100644 resources/sound/en/sound033.wav create mode 100644 resources/sound/en/sound034.wav create mode 100644 resources/sound/en/sound035.wav create mode 100644 resources/sound/en/sound036.wav create mode 100644 resources/sound/en/sound037.wav create mode 100644 resources/sound/en/sound038.wav create mode 100644 resources/sound/en/sound039.wav create mode 100644 resources/sound/en/sound040.wav create mode 100644 resources/sound/en/sound041.wav create mode 100644 resources/sound/en/sound042.wav create mode 100644 resources/sound/en/sound043.wav create mode 100644 resources/sound/en/sound044.wav create mode 100644 resources/sound/en/sound045.wav create mode 100644 resources/sound/en/sound046.wav create mode 100644 resources/sound/en/sound047.wav create mode 100644 resources/sound/en/sound048.wav create mode 100644 resources/sound/en/sound049.wav create mode 100644 resources/sound/en/sound050.wav create mode 100644 resources/sound/en/sound051.wav create mode 100644 resources/sound/en/sound052.wav create mode 100644 resources/sound/en/sound053.wav create mode 100644 resources/sound/en/sound054.wav create mode 100644 resources/sound/en/sound055.wav create mode 100644 resources/sound/en/sound056.wav create mode 100644 resources/sound/en/sound057.wav create mode 100644 resources/sound/en/sound058.wav create mode 100644 resources/sound/en/sound059.wav create mode 100644 resources/sound/en/sound060.wav create mode 100644 resources/sound/en/sound061.wav create mode 100644 resources/sound/en/sound062.wav create mode 100644 resources/sound/en/sound063.wav create mode 100644 resources/sound/en/sound064.wav create mode 100644 resources/sound/en/sound065.wav create mode 100644 resources/sound/en/sound066.wav create mode 100644 resources/sound/en/sound067.wav create mode 100644 resources/sound/en/sound068.wav create mode 100644 resources/sound/en/sound069.wav create mode 100644 resources/sound/en/sound070.wav create mode 100644 resources/sound/en/sound071.wav create mode 100644 resources/sound/en/sound072.wav create mode 100644 resources/sound/en/sound073.wav create mode 100644 resources/sound/en/sound074.wav create mode 100644 resources/sound/en/sound075.wav create mode 100644 resources/sound/en/sound076.wav create mode 100644 resources/sound/en/sound077.wav create mode 100644 resources/sound/en/sound078.wav create mode 100644 resources/sound/en/sound079.wav create mode 100644 resources/sound/en/sound080.wav create mode 100644 resources/sound/en/sound081.wav create mode 100644 resources/sound/en/sound082.wav create mode 100644 resources/sound/en/sound083.wav create mode 100644 resources/sound/en/sound084.wav create mode 100644 resources/sound/en_US/sound002.wav create mode 100644 resources/sound/en_US/sound003.wav create mode 100644 resources/sound/en_US/sound004.wav create mode 100644 resources/sound/en_US/sound005.wav create mode 100644 resources/sound/en_US/sound006.wav create mode 100644 resources/sound/en_US/sound007.wav create mode 100644 resources/sound/en_US/sound008.wav create mode 100644 resources/sound/en_US/sound009.wav create mode 100644 resources/sound/en_US/sound010.wav create mode 100644 resources/sound/en_US/sound014.wav create mode 100644 resources/sound/en_US/sound017.wav create mode 100644 resources/sound/en_US/sound018.wav create mode 100644 resources/sound/en_US/sound019.wav create mode 100644 resources/sound/en_US/sound027.wav create mode 100644 resources/sound/en_US/sound033.wav create mode 100644 resources/sound/en_US/sound037.wav create mode 100644 resources/sound/en_US/sound056.wav create mode 100644 resources/sound/en_US/sound057.wav create mode 100644 resources/sound/en_US/sound058.wav create mode 100644 resources/sound/en_US/sound059.wav create mode 100644 resources/sound/en_US/sound060.wav create mode 100644 resources/sound/en_US/sound061.wav create mode 100644 resources/sound/en_US/sound062.wav create mode 100644 resources/sound/en_US/sound063.wav create mode 100644 resources/sound/en_US/sound064.wav create mode 100644 resources/sound/en_US/sound065.wav create mode 100644 resources/sound/en_US/sound066.wav create mode 100644 resources/sound/en_US/sound067.wav create mode 100644 resources/sound/en_US/sound068.wav create mode 100644 resources/sound/en_US/sound069.wav create mode 100644 resources/sound/en_US/sound070.wav create mode 100644 resources/sound/en_US/sound071.wav create mode 100644 resources/sound/en_US/sound072.wav create mode 100644 resources/sound/en_US/sound073.wav create mode 100644 resources/sound/fr/sound002.wav create mode 100644 resources/sound/fr/sound003.wav create mode 100644 resources/sound/fr/sound004.wav create mode 100644 resources/sound/fr/sound005.wav create mode 100644 resources/sound/fr/sound006.wav create mode 100644 resources/sound/fr/sound007.wav create mode 100644 resources/sound/fr/sound008.wav create mode 100644 resources/sound/fr/sound009.wav create mode 100644 resources/sound/fr/sound010.wav create mode 100644 resources/sound/fr/sound014.wav create mode 100644 resources/sound/fr/sound017.wav create mode 100644 resources/sound/fr/sound018.wav create mode 100644 resources/sound/fr/sound019.wav create mode 100644 resources/sound/fr/sound027.wav create mode 100644 resources/sound/fr/sound033.wav create mode 100644 resources/sound/fr/sound037.wav create mode 100644 resources/sound/fr/sound056.wav create mode 100644 resources/sound/fr/sound057.wav create mode 100644 resources/sound/fr/sound058.wav create mode 100644 resources/sound/fr/sound059.wav create mode 100644 resources/sound/fr/sound060.wav create mode 100644 resources/sound/fr/sound061.wav create mode 100644 resources/sound/fr/sound062.wav create mode 100644 resources/sound/fr/sound063.wav create mode 100644 resources/sound/fr/sound064.wav create mode 100644 resources/sound/fr/sound065.wav create mode 100644 resources/sound/fr/sound066.wav create mode 100644 resources/sound/fr/sound067.wav create mode 100644 resources/sound/fr/sound068.wav create mode 100644 resources/sound/fr/sound069.wav create mode 100644 resources/sound/fr/sound070.wav create mode 100644 resources/sound/fr/sound071.wav create mode 100644 resources/sound/fr/sound072.wav create mode 100644 resources/sound/fr/sound073.wav create mode 100644 resources/sound/he/sound002.wav create mode 100644 resources/sound/he/sound003.wav create mode 100644 resources/sound/he/sound004.wav create mode 100644 resources/sound/he/sound005.wav create mode 100644 resources/sound/he/sound006.wav create mode 100644 resources/sound/he/sound007.wav create mode 100644 resources/sound/he/sound008.wav create mode 100644 resources/sound/he/sound009.wav create mode 100644 resources/sound/he/sound010.wav create mode 100644 resources/sound/he/sound014.wav create mode 100644 resources/sound/he/sound017.wav create mode 100644 resources/sound/he/sound018.wav create mode 100644 resources/sound/he/sound019.wav create mode 100644 resources/sound/he/sound027.wav create mode 100644 resources/sound/he/sound033.wav create mode 100644 resources/sound/he/sound037.wav create mode 100644 resources/sound/he/sound056.wav create mode 100644 resources/sound/he/sound057.wav create mode 100644 resources/sound/he/sound058.wav create mode 100644 resources/sound/he/sound059.wav create mode 100644 resources/sound/he/sound060.wav create mode 100644 resources/sound/he/sound061.wav create mode 100644 resources/sound/he/sound062.wav create mode 100644 resources/sound/he/sound063.wav create mode 100644 resources/sound/he/sound064.wav create mode 100644 resources/sound/he/sound065.wav create mode 100644 resources/sound/he/sound066.wav create mode 100644 resources/sound/he/sound067.wav create mode 100644 resources/sound/he/sound068.wav create mode 100644 resources/sound/he/sound069.wav create mode 100644 resources/sound/he/sound070.wav create mode 100644 resources/sound/he/sound071.wav create mode 100644 resources/sound/he/sound072.wav create mode 100644 resources/sound/he/sound073.wav create mode 100644 resources/sound/it/sound002.wav create mode 100644 resources/sound/it/sound003.wav create mode 100644 resources/sound/it/sound004.wav create mode 100644 resources/sound/it/sound005.wav create mode 100644 resources/sound/it/sound006.wav create mode 100644 resources/sound/it/sound007.wav create mode 100644 resources/sound/it/sound008.wav create mode 100644 resources/sound/it/sound009.wav create mode 100644 resources/sound/it/sound010.wav create mode 100644 resources/sound/it/sound014.wav create mode 100644 resources/sound/it/sound017.wav create mode 100644 resources/sound/it/sound018.wav create mode 100644 resources/sound/it/sound019.wav create mode 100644 resources/sound/it/sound027.wav create mode 100644 resources/sound/it/sound033.wav create mode 100644 resources/sound/it/sound037.wav create mode 100644 resources/sound/it/sound056.wav create mode 100644 resources/sound/it/sound057.wav create mode 100644 resources/sound/it/sound058.wav create mode 100644 resources/sound/it/sound059.wav create mode 100644 resources/sound/it/sound060.wav create mode 100644 resources/sound/it/sound061.wav create mode 100644 resources/sound/it/sound062.wav create mode 100644 resources/sound/it/sound063.wav create mode 100644 resources/sound/it/sound064.wav create mode 100644 resources/sound/it/sound065.wav create mode 100644 resources/sound/it/sound066.wav create mode 100644 resources/sound/it/sound067.wav create mode 100644 resources/sound/it/sound068.wav create mode 100644 resources/sound/it/sound069.wav create mode 100644 resources/sound/it/sound070.wav create mode 100644 resources/sound/it/sound071.wav create mode 100644 resources/sound/it/sound072.wav create mode 100644 resources/sound/it/sound073.wav create mode 100644 resources/win32/planetblupi.rc.in create mode 100644 src/.clang-format create mode 100644 src/action.cxx create mode 100644 src/action.h create mode 100644 src/blupi.cxx create mode 100644 src/blupi.h create mode 100644 src/button.cxx create mode 100644 src/button.h create mode 100644 src/config.h.in create mode 100644 src/decblupi.cxx create mode 100644 src/decgoal.cxx create mode 100644 src/decgoal.h create mode 100644 src/decio.cxx create mode 100644 src/decmap.cxx create mode 100644 src/decmove.cxx create mode 100644 src/decmove.h create mode 100644 src/decor.cxx create mode 100644 src/decor.h create mode 100644 src/decstat.cxx create mode 100644 src/def.h create mode 100644 src/display.cxx create mode 100644 src/display.h create mode 100644 src/event.cxx create mode 100644 src/event.h create mode 100644 src/fifo.cxx create mode 100644 src/fifo.h create mode 100644 src/fix.cxx create mode 100644 src/fog.cxx create mode 100644 src/gettext.h create mode 100644 src/json/json.hpp create mode 100644 src/menu.cxx create mode 100644 src/menu.h create mode 100644 src/misc.cxx create mode 100644 src/misc.h create mode 100644 src/movie.cxx create mode 100644 src/movie.h create mode 100644 src/obstacle.cxx create mode 100644 src/path.cxx create mode 100644 src/pixmap.cxx create mode 100644 src/pixmap.h create mode 100644 src/platform.h create mode 100644 src/platform/platform_js.cxx create mode 100644 src/platform/platform_sdl.cxx create mode 100644 src/progress.cxx create mode 100644 src/progress.h create mode 100644 src/sound.cxx create mode 100644 src/sound.h create mode 100644 src/text.cxx create mode 100644 src/text.h diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9e79ebd --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*.{cpp,h}] +indent_style = tab +indent_size = 4 +insert_final_newline = true diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..176a458 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..018ab4f --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/Debug/ +/Release/ +/build/ +.directory +*.kdev4 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e69de29 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..5723efd --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,426 @@ + +cmake_minimum_required (VERSION 3.2) + +set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") +set (CMAKE_CXX_STANDARD 11) + +include (GNUInstallDirs) +include (${CMAKE_ROOT}/Modules/ExternalProject.cmake) +include ("${CMAKE_SOURCE_DIR}/cmake/Ronn2Man.cmake") + +include_directories (${CMAKE_INSTALL_PREFIX}/include) +include_directories (${CMAKE_INSTALL_PREFIX}/include/SDL2) +link_directories (${CMAKE_INSTALL_PREFIX}/lib) + +project (planetblupi) +set (PB_VERSION_MAJOR 1) +set (PB_VERSION_MINOR 14) +set (PB_VERSION_PATCH 2) +set (PB_VERSION_EXTRA "") +set (PB_PRODUCT_NAME "Planet Blupi") +set (PB_PACKAGE_NAME "planetblupi") +set (PB_EXEC "planetblupi") +set (PB_ICON_REF "blupi") +set (PB_DESCRIPTION "Planet Blupi - A delirious spell-binding game") + +option (PB_HTTP_VERSION_CHECK "Run a version check over HTTP (with CURL)" OFF) + +configure_file ( + "${PROJECT_SOURCE_DIR}/src/config.h.in" + "${PROJECT_BINARY_DIR}/include/config.h" +) + +include_directories ("${PROJECT_BINARY_DIR}/include") + +if (BUILD_JS) + file (GLOB sources src/*.cxx src/*.h src/json/* src/platform/*_js.*) +else () + file (GLOB sources src/*.cxx src/*.h src/json/* src/platform/*_sdl.*) +endif () + +file (GLOB_RECURSE po resources/po/*.po) + +if (APPIMAGE_APPRUN_PROGRAM AND APPIMAGE_ASSISTANT_PROGRAM) + set (USE_APPIMAGE ON) +endif () + +if (NOT USE_APPIMAGE) + configure_file ( + "${PROJECT_SOURCE_DIR}/resources/linux/application.desktop.in" + "${CMAKE_CURRENT_BINARY_DIR}/${PB_PACKAGE_NAME}.desktop" + @ONLY + ) +endif () + +set (planetblupi_OUTPUT planetblupi) + +if (NOT DEFINED BUILD_LINUX) + set (BUILD_LINUX UNIX AND NOT APPLE) +endif () + +if (BUILD_JS) + set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} ${EMSCRIPTEN_FLAGS}) + set (CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} "--preload-file share") + set (planetblupi_OUTPUT planetblupi.html) +endif () + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11 -L${CMAKE_INSTALL_PREFIX}/lib") +endif () + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND "${STATIC_BUILD}") + set (CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} "-static-libgcc -static-libstdc++") +endif () + +if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -DDEBUG") +endif () + +if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release") + set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s") + set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s") +endif () + +# These copies are necessary with our stuff for AppImage because it's not +# supported by CPack. +if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + file (COPY resources/data DESTINATION share/planetblupi) +else () + file ( + COPY resources/data DESTINATION share/planetblupi + PATTERN "world2*.blp" EXCLUDE + PATTERN "world*.dev.blp" EXCLUDE + ) +endif () +file (COPY resources/image DESTINATION share/planetblupi) +if (NOT BUILD_JS) + file (COPY resources/movie DESTINATION share/planetblupi) +endif () +file (COPY resources/sound DESTINATION share/planetblupi) +file (COPY resources/music DESTINATION share/planetblupi) +file (COPY LICENSE.all DESTINATION share/doc/planetblupi) +file (COPY COPYING DESTINATION share/doc/planetblupi) +file (RENAME "${CMAKE_BINARY_DIR}/share/doc/planetblupi/LICENSE.all" + "${CMAKE_BINARY_DIR}/share/doc/planetblupi/copyright") + +if (BUILD_LINUX) + file (COPY resources/icon/hicolor DESTINATION share/icons) + file ( + COPY resources/linux/${PB_PACKAGE_NAME}.appdata.xml + DESTINATION share/metainfo + ) +endif () + +# Windows stuff + +if (MINGW) + file (COPY resources/icon/blupi.ico DESTINATION "${CMAKE_BINARY_DIR}") + configure_file ( + "${CMAKE_CURRENT_SOURCE_DIR}/resources/win32/planetblupi.rc.in" + "${CMAKE_BINARY_DIR}/planetblupi.rc" + @ONLY + ) + + list (APPEND sources "${CMAKE_BINARY_DIR}/planetblupi.rc") + + set (CMAKE_RC_COMPILER_INIT windres) + enable_language (RC) + set (CMAKE_RC_COMPILE_OBJECT " -O coff -i -o ") + + # Remove cmd window when executing planetblupi + set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mwindows") +endif (MINGW) + +# Dependencies + +if ("${STATIC_BUILD}") + set (CMAKE_INCLUDE_PATH ${CMAKE_INSTALL_PREFIX}/include) + set (CMAKE_LIBRARY_PATH ${CMAKE_INSTALL_PREFIX}/lib) +endif () + +find_package (Intl REQUIRED) +include_directories (${Intl_INCLUDE_DIRS}) + +find_package (Iconv REQUIRED) +include_directories (${Iconv_INCLUDE_DIRS}) + +find_package (Argagg REQUIRED) +include_directories (${Argagg_INCLUDE_DIRS}) + +find_package (SDLKitchensink REQUIRED) +include_directories (${SDLKitchensink_INCLUDE_DIRS}) + +find_package (PkgConfig REQUIRED) +if (NOT BUILD_JS) + pkg_search_module (SDL2 REQUIRED sdl2) + set (planetblupi_DEPS ${planetblupi_DEPS} ${SDL2_STATIC_LIBRARIES}) + pkg_search_module (SDL2_IMAGE REQUIRED SDL2_image) + set (planetblupi_DEPS ${planetblupi_DEPS} ${SDL2_IMAGE_STATIC_LIBRARIES}) + pkg_search_module (SDL2_MIXER REQUIRED SDL2_mixer) + set (planetblupi_DEPS ${planetblupi_DEPS} ${SDL2_MIXER_STATIC_LIBRARIES}) +endif () + +if (${PB_HTTP_VERSION_CHECK}) + pkg_search_module (CURL REQUIRED libcurl) + add_definitions (-DUSE_CURL) +endif () + +if ("${STATIC_BUILD}") + # Static dependencies for SDL_kitchensink + pkg_search_module (AVCODEC REQUIRED libavcodec) + pkg_search_module (AVFORMAT REQUIRED libavformat) + pkg_search_module (AVUTIL REQUIRED libavutil) + pkg_search_module (SWSCALE REQUIRED libswscale) + pkg_search_module (SWRESAMPLE REQUIRED libswresample) + + if (NOT BUILD_JS) + pkg_search_module (PNG REQUIRED libpng) + set (planetblupi_DEPS ${planetblupi_DEPS} ${PNG_STATIC_LIBRARIES}) + + # Static dependencies for SDL_mixer + pkg_search_module (VORBIS REQUIRED vorbisfile) + set (planetblupi_DEPS ${planetblupi_DEPS} ${VORBIS_STATIC_LIBRARIES}) + + if (BUILD_LINUX) + pkg_search_module (ALSA REQUIRED alsa) + pkg_search_module (PULSE REQUIRED libpulse) + endif () + + set (planetblupi_DEPS ${planetblupi_DEPS} + ${Intl_LIBRARIES} + ${Iconv_LIBRARIES} + ) + endif () + + if (${PB_HTTP_VERSION_CHECK}) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DCURL_STATICLIB") + endif () +endif () + +########################### +## Main binary dependencies +########################### + +add_executable (${planetblupi_OUTPUT} ${sources}) + +if ("${STATIC_BUILD}") + set (planetblupi_DEPS ${planetblupi_DEPS} + ${SDLKitchensink_STATIC_LIBRARIES} + ${AVCODEC_STATIC_LIBRARIES} + ${AVFORMAT_STATIC_LIBRARIES} + ${AVUTIL_STATIC_LIBRARIES} + ${SWSCALE_STATIC_LIBRARIES} + ${SWRESAMPLE_STATIC_LIBRARIES} + ) + + if (${PB_HTTP_VERSION_CHECK}) + list (APPEND planetblupi_DEPS + ${CURL_STATIC_LIBRARIES} + ) + endif () + + if (BUILD_LINUX) + list (APPEND planetblupi_DEPS + ${ALSA_STATIC_LIBRARIES} + ${PULSE_STATIC_LIBRARIES} + ) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_INSTALL_PREFIX}/lib/pulseaudio") + endif () +else () + set (planetblupi_DEPS + ${SDL2_LIBRARIES} + ${SDL2_MIXER_LIBRARIES} + ${SDL2_IMAGE_LIBRARIES} + ${CURL_LIBRARIES} + ${SDLKitchensink_LIBRARIES} + pthread + ) + + if (${PB_HTTP_VERSION_CHECK}) + list (APPEND planetblupi_DEPS + ${CURL_LIBRARIES} + ) + endif () +endif () + +target_link_libraries (${planetblupi_OUTPUT} PUBLIC ${planetblupi_DEPS}) + +########## +## GetText +########## + +find_package (Gettext) + +set (_potFile ${CMAKE_CURRENT_SOURCE_DIR}/resources/po/${PROJECT_NAME}.pot) + +add_custom_command (OUTPUT ${_potFile} + COMMAND xgettext --no-location --keyword=translate -o ${_potFile} ${sources} + DEPENDS ${sources} + COMMENT "Extract translatable messages to ${_potFile}" +) + +add_custom_target (pot_file ALL ${_all} + DEPENDS ${_potFile} +) + +gettext_create_translations (${_potFile} ALL ${po}) + +## Put mo files to appropriate directory +foreach (file ${_gmoFiles}) + get_filename_component (_lang ${file} NAME_WE) + set (_out "share/locale/${_lang}/LC_MESSAGES") + + add_custom_command (OUTPUT ${_out}/planetblupi.mo + COMMAND ${CMAKE_COMMAND} -E copy ${file} ${_out}/planetblupi.mo + DEPENDS translations ${file} + ) + + add_custom_target ("po-${_lang}" ALL ${_all} + DEPENDS ${_out}/planetblupi.mo + ) + + add_dependencies (${planetblupi_OUTPUT} "po-${_lang}") +endforeach (file) + +######### +# manpage +######### + +add_manpage_target () +manpage(${PROJECT_NAME} 6) + +############## +# Installation +############## + +if (NOT BUILD_JS) + install (TARGETS ${planetblupi_OUTPUT} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + install ( + DIRECTORY resources/data DESTINATION share/planetblupi + PATTERN "world2*.blp" EXCLUDE + PATTERN "world*.dev.blp" EXCLUDE + ) + install ( + DIRECTORY resources/data DESTINATION share/planetblupi + CONFIGURATIONS Debug + PATTERN "world2*.blp" + PATTERN "world*.dev.blp" + ) + install (DIRECTORY resources/image DESTINATION share/planetblupi) + install (DIRECTORY resources/movie DESTINATION share/planetblupi) + install (DIRECTORY resources/sound DESTINATION share/planetblupi) + install (DIRECTORY resources/music DESTINATION share/planetblupi) + install (FILES LICENSE.all DESTINATION share/doc/planetblupi RENAME copyright) + install (FILES COPYING DESTINATION share/doc/planetblupi) + + if (BUILD_LINUX) + install (DIRECTORY resources/icon/hicolor DESTINATION share/icons) + install ( + FILES resources/linux/${PB_PACKAGE_NAME}.appdata.xml + DESTINATION share/metainfo + ) + endif () + + if (NOT USE_APPIMAGE) + install ( + FILES ${CMAKE_CURRENT_BINARY_DIR}/${PB_PACKAGE_NAME}.desktop + DESTINATION share/applications + ) + endif () + + # Copy libwinpthread-1.dll which seems not be linkable statically + if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows" AND MINGW) + execute_process (COMMAND cygpath.exe --windows $ENV{MINGW_PREFIX} OUTPUT_VARIABLE MINGW_PATH) + string (REGEX REPLACE "[ \t\n\r]+$" "" MINGW_PATH "${MINGW_PATH}") + string (REGEX REPLACE "[\\]" "\\\\\\\\" MINGW_PATH "${MINGW_PATH}") + install (FILES "${MINGW_PATH}\\\\bin\\\\libwinpthread-1.dll" DESTINATION bin) + endif () +endif () + +######### +## Deploy +######### + +if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release" AND "${STATIC_BUILD}") + # set (CPACK_STRIP_FILES TRUE) + set (CPACK_PACKAGE_NAME ${PB_PACKAGE_NAME}) + set (CPACK_PACKAGE_VENDOR "blupi.org") + set (CPACK_PACKAGE_DESCRIPTION_SUMMARY ${PB_DESCRIPTION}) + set (CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") + # set (CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README-user.md") + set (CPACK_PACKAGE_FILE_NAME ${PB_PACKAGE_NAME}) + set (CPACK_PACKAGE_VERSION "${PB_VERSION_MAJOR}.${PB_VERSION_MINOR}.${PB_VERSION_PATCH}${PB_VERSION_EXTRA}") + set (CPACK_PACKAGE_INSTALL_DIRECTORY ${PB_PRODUCT_NAME}) + set (CPACK_PACKAGE_EXECUTABLES "planetblupi;Planet Blupi") + + if (USE_APPIMAGE) + include (LinuxAppImageBuild) + set (CMAKE_PACKAGED_OUTPUT_PREFIX ${CMAKE_INSTALL_PREFIX}) + APPIMAGE_PACKAGE (planetblupi ${PB_PACKAGE_NAME} ${PB_PRODUCT_NAME} "${CMAKE_CURRENT_SOURCE_DIR}/resources/linux" "${CMAKE_BINARY_DIR}/share" "" "" ${PB_ICON_REF} SIGN_APP) + elseif (MINGW) + set (INSTALLER_FILE_NAME "${PB_PACKAGE_NAME}-${PB_VERSION_MAJOR}.${PB_VERSION_MINOR}.${PB_VERSION_PATCH}${PB_VERSION_EXTRA}") + set (CPACK_PACKAGE_FILE_NAME "${INSTALLER_FILE_NAME}") + set (CPACK_GENERATOR "NSIS64") + set (CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}\\\\resources\\\\nsis\\\\installer.bmp") + set (CPACK_NSIS_COMPRESSOR "/SOLID lzma") + set (CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\planetblupi.exe") + set (CPACK_NSIS_URL_INFO_ABOUT "http://www.blupi.org") + set (CPACK_NSIS_MUI_FINISHPAGE_RUN "planetblupi") + if (SIGN_APP) + set (CPACK_NSIS_SIGN_UNINSTALLER "sign -a -fd sha1 -t http://time.certum.pl -v") + endif () + + include (CPack) + + find_program (SIGNTOOL_EXECUTABLE signtool) + if (SIGN_APP AND SIGNTOOL_EXECUTABLE) + add_custom_command (TARGET planetblupi + POST_BUILD + COMMAND ${SIGNTOOL_EXECUTABLE} + sign -a -fd sha1 -t http://time.certum.pl -v + "${CMAKE_BINARY_DIR}/planetblupi.exe") + endif () + + add_custom_command (TARGET planetblupi + POST_BUILD + COMMAND make package) + + if (SIGN_APP AND SIGNTOOL_EXECUTABLE) + add_custom_command (TARGET planetblupi + POST_BUILD + COMMAND ${SIGNTOOL_EXECUTABLE} + sign -a -fd sha1 -t http://time.certum.pl + "${CMAKE_BINARY_DIR}/${INSTALLER_FILE_NAME}.exe") + endif () + elseif (APPLE) + set (CPACK_GENERATOR "Bundle") + set (CPACK_BUNDLE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/resources/darwin/icon.icns") + set (CPACK_BUNDLE_NAME ${PB_PRODUCT_NAME}) + set (CPACK_BUNDLE_PLIST "${CMAKE_BINARY_DIR}/Info.plist") + set (CPACK_BUNDLE_STARTUP_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/resources/darwin/Planet Blupi") + if (SIGN_APP) + set (CPACK_BUNDLE_APPLE_CERT_APP "Developer ID Application: Mathieu Schroeter") + endif () + set (CPACK_PACKAGE_FILE_NAME "planetblupi-${PB_VERSION_MAJOR}.${PB_VERSION_MINOR}.${PB_VERSION_PATCH}${PB_VERSION_EXTRA}") + + set (CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_CURRENT_SOURCE_DIR}/resources/darwin/background.tiff") + set (CPACK_DMG_DS_STORE_SETUP_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/resources/darwin/dmgsetup.scpt") + + set (BUNDLE_VERSION "${PB_VERSION_MAJOR}.${PB_VERSION_MINOR}.${PB_VERSION_PATCH}${PB_VERSION_EXTRA}") + set (BUNDLE_IDENTIFIER "org.blupi.planet") + set (BUNDLE_ICON_REF "Planet Blupi") + + configure_file ( + "${CMAKE_CURRENT_SOURCE_DIR}/resources/darwin/Info.plist.in" + "${CMAKE_BINARY_DIR}/Info.plist" + @ONLY + ) + + include (CPack) + add_custom_command (TARGET planetblupi + POST_BUILD + COMMAND make package) + endif () +endif () diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..c627928 --- /dev/null +++ b/COPYING @@ -0,0 +1,29 @@ +# Copying + +| Years | People | +| --------- | ---------------------------------------------------------------- | +| | **Developers** | +| 1997 | Daniel Roux and Denis Dumoulin | +| 2017-2019 | Mathieu Schroeter | +| | | +| | **Voices** | +| 1997 | Daniel Roux, David Besuchet, Michael Walz and Garry Goodman | +| | | +| | **Translators** | +| 1997 | Christian Alleyn, Michael Walz, David Besuchet, Cedric Freeman, | +| | Adrienne Magnin and Wendy de Pauli | +| 2005 | Rodolfo Andrade de Oliveira and Vanessa Alexandre Vieira | +| 2017 | Catia Guidi and Mateusz Lis | +| 2019 | punctdan _(@github)_ and TheShwarma _(@twitter)_ | +| | | +| | **Missions** | +| 1997 | Daniel Roux, Adrien Roux and Denis Dumoulin | +| | | +| | **Testers** | +| 1997 | Denis Dumoulin, Adrien Roux, Michael Walz, René Beuchat, | +| | Pierre Arnaud, Michèle Cottler, Arnaud Cottler, Daniel Durussel, | +| | Audrey Durussel, Laurianne Durussel, Philippe Menu, | +| | Michael Bloch, Florian Stutzmann, Fabrice Bodmer, | +| | Rachel Besuchet, Pauline Rochat, Antoine Richoy, | +| | Fabrice Marquis, Steve Guex, Simon Lopez, David Piot, | +| | Yves Burgos and Jeremy Kull | diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..dea8bbe --- /dev/null +++ b/LICENSE @@ -0,0 +1,696 @@ + +This game is linked on some static libraries: + + argagg (MIT) + FFmpeg (LGPLv2.1) + GNU/gettext (GPLv3) + libcurl (MIT/X derivate) + GNU/libiconv (GPLv3) + libogg (own license) + libpng (own license) + libsndfile (LGPLv3) + libvorbis (own license) + SDL_kitchensink (MIT) + SDL2 (zlib license) + SDL2_image (zlib license) + SDL2_mixer (zlib license) + zlib (own license) + + +Planet Blupi is licensed under GPLv3, see LICENSE.all/copyright for details. + + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/LICENSE.all b/LICENSE.all new file mode 100644 index 0000000..7c593ef --- /dev/null +++ b/LICENSE.all @@ -0,0 +1,3669 @@ + +List of all licenses, concerns Planet Blupi and dependencies + + * argagg -- https://github.com/vietjtnguyen/argagg + * FFmpeg -- https://www.ffmpeg.org + * GNU/gettext -- https://www.gnu.org/software/gettext/ + * libasound -- https://www.alsa-project.org + * libcurl -- https://curl.haxx.se/libcurl/ + * GNU/libiconv -- https://www.gnu.org/software/libiconv/ + * libogg -- https://xiph.org/downloads/ + * libpng -- http://www.libpng.org/pub/png/libpng.html + * libpulse -- https://freedesktop.org/software/pulseaudio/doxygen/ + * libsndfile -- http://www.mega-nerd.com/libsndfile/ + * libvorbis -- https://xiph.org/downloads/ + * SDL_kitchensink -- https://github.com/katajakasa/SDL_kitchensink + * SDL2 -- https://www.libsdl.org + * SDL2_image -- https://www.libsdl.org/projects/SDL_image/ + * SDL2_mixer -- https://www.libsdl.org/projects/SDL_mixer/ + * zlib -- https://zlib.net/ + +###################################################################### +# Planet Blupi - LICENSE +###################################################################### + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + +###################################################################### +# argagg - LICENSE +###################################################################### + +Copyright (c) 2017 Viet The Nguyen + +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. + +###################################################################### +# FFmpeg - LICENSE +###################################################################### + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + +###################################################################### +# libasound - LICENSE +###################################################################### + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + +###################################################################### +# GNU/gettext - LICENSE +###################################################################### + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + +###################################################################### +# libcurl - LICENSE +###################################################################### + +COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 1996 - 2017, Daniel Stenberg, , and many +contributors, see the THANKS file. + +All rights reserved. + +Permission to use, copy, modify, and distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright +notice and this permission notice appear in all copies. + +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 OF THIRD PARTY RIGHTS. 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. + +Except as contained in this notice, the name of a copyright holder shall not +be used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization of the copyright holder. + +###################################################################### +# GNU/libiconv - LICENSE +###################################################################### + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + +###################################################################### +# libogg - LICENSE +###################################################################### + +Copyright (c) 2002, Xiph.org Foundation + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- 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. + +- Neither the name of the Xiph.org Foundation nor the names of its +contributors may 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 FOUNDATION +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. + +###################################################################### +# libpng - LICENSE +###################################################################### + +This copy of the libpng notices is provided for your convenience. In case of +any discrepancy between this copy and the notices in the file png.h that is +included in the libpng distribution, the latter shall prevail. + +COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: + +If you modify libpng you may insert additional notices immediately following +this sentence. + +This code is released under the libpng license. + +libpng versions 1.0.7, July 1, 2000 through 1.6.28, January 5, 2017 are +Copyright (c) 2000-2002, 2004, 2006-2017 Glenn Randers-Pehrson, are +derived from libpng-1.0.6, and are distributed according to the same +disclaimer and license as libpng-1.0.6 with the following individuals +added to the list of Contributing Authors: + + Simon-Pierre Cadieux + Eric S. Raymond + Mans Rullgard + Cosmin Truta + Gilles Vollant + James Yu + Mandar Sahastrabuddhe + +and with the following additions to the disclaimer: + + There is no warranty against interference with your enjoyment of the + library or against infringement. There is no warranty that our + efforts or the library will fulfill any of your particular purposes + or needs. This library is provided with all faults, and the entire + risk of satisfactory quality, performance, accuracy, and effort is with + the user. + +Some files in the "contrib" directory and some configure-generated +files that are distributed with libpng have other copyright owners and +are released under other open source licenses. + +libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are +Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from +libpng-0.96, and are distributed according to the same disclaimer and +license as libpng-0.96, with the following individuals added to the list +of Contributing Authors: + + Tom Lane + Glenn Randers-Pehrson + Willem van Schaik + +libpng versions 0.89, June 1996, through 0.96, May 1997, are +Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, +and are distributed according to the same disclaimer and license as +libpng-0.88, with the following individuals added to the list of +Contributing Authors: + + John Bowler + Kevin Bracey + Sam Bushell + Magnus Holmgren + Greg Roelofs + Tom Tanner + +Some files in the "scripts" directory have other copyright owners +but are released under this license. + +libpng versions 0.5, May 1995, through 0.88, January 1996, are +Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + +For the purposes of this copyright and license, "Contributing Authors" +is defined as the following set of individuals: + + Andreas Dilger + Dave Martindale + Guy Eric Schalnat + Paul Schmidt + Tim Wegner + +The PNG Reference Library is supplied "AS IS". The Contributing Authors +and Group 42, Inc. disclaim all warranties, expressed or implied, +including, without limitation, the warranties of merchantability and of +fitness for any purpose. The Contributing Authors and Group 42, Inc. +assume no liability for direct, indirect, incidental, special, exemplary, +or consequential damages, which may result from the use of the PNG +Reference Library, even if advised of the possibility of such damage. + +Permission is hereby granted to use, copy, modify, and distribute this +source code, or portions hereof, for any purpose, without fee, subject +to the following restrictions: + + 1. The origin of this source code must not be misrepresented. + + 2. Altered versions must be plainly marked as such and must not + be misrepresented as being the original source. + + 3. This Copyright notice may not be removed or altered from any + source or altered source distribution. + +The Contributing Authors and Group 42, Inc. specifically permit, without +fee, and encourage the use of this source code as a component to +supporting the PNG file format in commercial products. If you use this +source code in a product, acknowledgment is not required but would be +appreciated. + +END OF COPYRIGHT NOTICE, DISCLAIMER, and LICENSE. + +TRADEMARK: + +The name "libpng" has not been registered by the Copyright owner +as a trademark in any jurisdiction. However, because libpng has +been distributed and maintained world-wide, continually since 1995, +the Copyright owner claims "common-law trademark protection" in any +jurisdiction where common-law trademark is recognized. + +OSI CERTIFICATION: + +Libpng is OSI Certified Open Source Software. OSI Certified Open Source is +a certification mark of the Open Source Initiative. OSI has not addressed +the additional disclaimers inserted at version 1.0.7. + +EXPORT CONTROL: + +The Copyright owner believes that the Export Control Classification +Number (ECCN) for libpng is EAR99, which means not subject to export +controls or International Traffic in Arms Regulations (ITAR) because +it is open source, publicly available software, that does not contain +any encryption software. See the EAR, paragraphs 734.3(b)(3) and +734.7(b). + +Glenn Randers-Pehrson +glennrp at users.sourceforge.net +January 5, 2017 + +###################################################################### +# libpulse - LICENSE +###################################################################### + +All PulseAudio source files, except as noted below, are licensed under the GNU +Lesser General Public License. (see file LGPL for details) + +However, the server side has optional GPL dependencies. These include the +libsamplerate and gdbm (core libraries), LIRC (lirc module) and FFTW (equalizer +module), although others may also be included in the future. If PulseAudio is +compiled with these optional components, this effectively downgrades the +license of the server part to GPL (see the file GPL for details), exercising +section 3 of the LGPL. In such circumstances, you should treat the client +library (libpulse) of PulseAudio as being LGPL licensed and the server part +(libpulsecore) as being GPL licensed. Since the PulseAudio daemon, tests, +various utilities/helpers and the modules link to libpulsecore and/or the afore +mentioned optional GPL dependencies they are of course also GPL licensed also +in this scenario. + +In addition to this, if D-Bus support is enabled, the PulseAudio client library +(libpulse) MAY need to be licensed under the GPL, depending on the license +adopted for libdbus. libdbus is licensed under either of the Academic Free +License 2.1 or GPL 2.0 or above. Which of these applies is your choice, and the +result affects the licensing of libpulse and thus, potentially, all programs +that link to libpulse. + +Andre Adrian's echo cancellation implementation is licensed under a less +restrictive license - see src/modules/echo-cancel/adrian-license.txt for +details. + +Some other files pulled into PA source (i.e. reference implementations that are +considered too small and stable to be considered as an external library) use the +more permissive MIT license. This include the device reservation DBus protocol +and realtime kit implementations. + +A more permissive BSD-style license is used for LFE filters, see +src/pulsecore/filter/LICENSE.WEBKIT for details. + +Additionally, a more permissive Sun license is used for code that performs +u-law, A-law and linear PCM conversions. + +The qpaeq program (src/utils/qpaeq) is licensed under the GNU Affero General +Public License (version 3, or any later version at your discretion). See the +file AGPL for details. + +While we attempt to provide a summary here, it is the ultimate responsibility of +the packager to ensure the components they use in their build of PulseAudio +meets their license requirements. + +###################################################################### +# libsndfile - LICENSE +###################################################################### + + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + +###################################################################### +# libogg - LICENSE +###################################################################### + +Copyright (c) 2002, Xiph.org Foundation + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- 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. + +- Neither the name of the Xiph.org Foundation nor the names of its +contributors may 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 FOUNDATION +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. + +###################################################################### +# SDL_kitchensink - LICENSE +###################################################################### + +The MIT License (MIT) + +Copyright (c) 2016 Tuomas Virtanen + +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. + +###################################################################### +# SDL2 - LICENSE +###################################################################### + +Simple DirectMedia Layer +Copyright (C) 1997-2017 Sam Lantinga + +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. + +###################################################################### +# SDL2_image - LICENSE +###################################################################### + +SDL_image: An example image loading library for use with SDL +Copyright (C) 1997-2016 Sam Lantinga + +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. + +###################################################################### +# SDL2_mixer - LICENSE +###################################################################### + +SDL_mixer: An audio mixer library based on the SDL library +Copyright (C) 1997-2016 Sam Lantinga + +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. + +###################################################################### +# zlib - LICENSE +###################################################################### + +zlib.h -- interface of the 'zlib' general purpose compression library +version 1.2.11, January 15th, 2017 + +Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler + +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. + +Jean-loup Gailly Mark Adler +jloup@gzip.org madler@alumni.caltech.edu + + +The data format used by the zlib library is described by RFCs (Request for +Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 +(zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). diff --git a/README.md b/README.md new file mode 100644 index 0000000..d2266dc --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# Planet Blupi + +![blupi](blupi.png) + +Please, do not use this repository directly for development but refer to the +bundle located at . + +See the [manpage](planetblupi.6.ronn) for a user README. + +## Original versions (1997) + +You can find "mostly" the original source code from previous versions (v1.7 and +v1.8, 1997) under the tags `v1.7.0` and `v1.8.0`. Note that both tags are +targetting the same commit. The reason is that the version 1.8 was done because +a bug was discovered on the cdroms (deployment problems only). diff --git a/README.translators.md b/README.translators.md new file mode 100644 index 0000000..af4c37e --- /dev/null +++ b/README.translators.md @@ -0,0 +1,81 @@ +# How to translate Planet Blupi + +## The interface + +All texts in the interface are using gettext PO files format. The files are +located in the `resources/po/` directory in the sources. For adding a new +translation, open the `resources/po/planetblupi.pot` file with an editor like +[poedit][1] for example. It can be a bit difficult to understand the context +without playing with your translations but there is a trick. Once you are ready +to test your translations, save your `.po` file and the corresponding `.mo` +file. Rename the `.mo` file to `planetblupi.mo`. Go to the directory where is +installed Planet Blupi and look at (for replacing the french translation by +yours for example) `share/locale/fr/LC_MESSAGES/` and put your `.mo` file in +this directory. You can replace an other lang if you like. + +> Under Windows OS, you should find the french translations in +> `C:\Program Files\Planet Blupi\share\locale\fr\LC_MESSAGES\`. +> With macOS it's possible to open the `Planet Blupi.app` and update the file +> directly in the `.app`. But note that it breaks the application signature. To +> start the game, maybe it's necessary to open via the context menu for by +> passing the macOS security. +> For Linux you must unpack the AppImage file somewhere for changing the files. + +Then start the game, the interface will use your new translation if you select +"Français" in the global settings screen. + +If you see some strange characters, like a square '□', then contact me and I +will add the necessary glyphs for your language. Planet Blupi is not using a +real font but just sprites with a limited range of characters. + +One text is hard-coded in the source code. It's the text for selecting the +language in the global settings screen (it's just the lang's name). Please, +don't forget to provide this one. + +```c + if (locale == "en") + lang = "English"; + else if (locale == "en_US") + lang = "American english"; + else if (locale == "fr") + lang = "Français"; + else if (locale == "de") + lang = "Deutsch"; + else if (locale == "it") + lang = "Italiano"; + else if (locale == "pl") + lang = "Polski"; + else if (locale == "tr") + lang = "Türkçe"; + else if (locale == "pt") + lang = "Português"; + else if (locale == "he") + lang = "עברית"; +``` + +## The missions + +The missions are located in the `resources/data/` directory. Open the +`en/stories.blp` with a text editor like Notepad++, Visual Studio Code, Sublime +Text, etc, ... Ensure to work in UTF-8. Like for the interface, you can replace +for example the french file by yours in the `share/planetblupi/data/fr/` +directory. + +## Some rules + +1. The "Planet Blupi" title must not be translated excepted if your language is + not using Latin-1 like Hebrew, Korean and Chinese for example. +2. If you plan to translate in Korean, ask me for details because I already have + most translations but I must (still) draw all glyphs. +3. Like for the Hebrew translations; I can enable the reversed game layout + (right to left reading) for your translation if necessary. + +## The voices + +It's not mandatory but it's very appreciate if you can provide the Blupi voices; +check this [README][2]. And if you don't know how to filter the sound in order +to produce a voice with an higher ton (like Blupi); contact me and I will help +you. + +[1]: https://poedit.net/ +[2]: README.voices.md diff --git a/README.voices.md b/README.voices.md new file mode 100644 index 0000000..bba64d6 --- /dev/null +++ b/README.voices.md @@ -0,0 +1,38 @@ +# Blupi voices + +| File | Context | en | en_US | fr | de | it | pl (proposal) | +| -------- | ---------------------------------- | --------------------- | ----------------------- | ----------------------- | ------------------- | ----------------- | --------------------- | +| sound056 | Blupi can't do what is asked for | I can't do that | I can't do it | J'y arrive pas | **?** | **?** | Nie mogę tego zrobić | +| sound057 | " | Impossible | Impossible | Impossible | **?** | **?** | Niemożliwe | +| sound058 | " | Oh no | No way | Mais non | Nein nein | **?** | Nie ma mowy | +| sound002 | Blupi is selected | Yes? | Yes? | Oui ? | Ja? | Si? | Tak? | +| sound003 | " | Hi! | Hi! | Ohé | **?** | **?** | Cześć! | +| sound004 | " | Master? | Yes Master! | Maître ? | Meister? | **?** | Tak szefie? | +| sound059 | " | What's the news? | What do you want? | C'est à quel sujet ? | **?** | **?** | W czym mogę pomóc? | +| sound060 | " | Hello boss | Hey boss | A vos ordres ! | **?** | **?** | Cześć szefie! | +| sound061 | " | What's up? | What's up? | Qu'est-ce qu'y y'a ? | Was ist los? | **?** | Co tam? | +| sound062 | Blupi is selected when he is tired | Not again | Not again | Ouaip ! | **?** | **?** | Tylko nie to | +| sound063 | " | I beg your pardon? | Pardon me? | J'vous demande pardon ? | Was ist los?! | **?** | Przepraszam? | +| sound064 | " | Now what? | Now what? | Quoi encore ! | Jaa! | **?** | I co teraz? | +| sound065 | Blupi is selected too many times | I'm fed up | I'm fed up | Ca suffit maint'nant. | **?** | **?** | Mam już dosyć | +| sound066 | " | Leave me alone | Leave me alone | Laissez-moi tranquille. | **?** | **?** | Zostaw mnie w spokoju | +| sound067 | " | You're driving me mad | You're driving me crazy | J'vais m'fâcher ! | **?** | **?** | Denerwujesz mnie | +| sound005 | Blupi begins an action | It won't be long | Okay | D'accord ! | Okay | Okay | Okej | +| sound006 | " | Let's go! | Let's go! | J'y vais | **?** | **?** | Idziemy! | +| sound007 | " | Just a sec | Just a sec | Un instant | **?** | Un momento | Chwilunia | +| sound068 | " ... if multiple selection | You're the boss | You're the boss | C'est vous l'patron | In Ordnung | **?** | Ty jesteś tu szefem | +| sound069 | " ... " | Why not? | Why not? | C'est d'accord | Alles klar | **?** | Czemu nie? | +| sound070 | " ... " | Right! | Alright! | Entendu | **?** | **?** | Jasne! | +| sound008 | Blupi has finished an action | There you are | There you are | Et voilà | **?** | **?** | I gotowe | +| sound009 | " | Done that | All done | J'y suis | Fertig | **?** | Wszystko zrobione | +| sound010 | " | Finish! | Finished! | Terminé! | Ich bin fertig | Finito! | Już! | +| sound071 | " | It's done | It's done | C'est fait | **?** | **?** | Zrobione | +| sound072 | " | It's finished | It's finished | C'est fini | Fertig | **?** | Skończone | +| sound073 | " | I've finished | I've finished | J'ai fini | Ich bin fertig | **?** | Skończyłem | +| sound014 | Blupi takes his momentum to jump | Hop! | Ha! | Hop! | Hop! | Boal! | Hop! | +| sound017 | Blupi is burning | Aaaouch! | AAAAaaaaahh! | Aaaaaaaahhhh... | Aouaah-aouahh | Aaaaaaaahhhh... | Ałłłć! | +| sound018 | Blupi dies of exhaustion | Chiuu...[pssst...] | Haaa...[pssst...] | Pffff...[hennnn...] | **?** | Haaa...[pffff...] | Fiu...[pssst...] | +| sound019 | Blupi eats tomatoes | Yummy-yummy | Yumm-yumm | Miam-miam | Mjam-mjam | **?** | Mniam-mniam | +| sound027 | Blupi catches a virus | A-tissue! | A-chu! | A-tchou! | **?** | **?** | A-psik! | +| sound033 | Blupi picks flowers | La-la-lalalala... ♪♫ | Laa-lalala... ♪♫ | Lalalalala... ♪♫ | Laa-lalalalaa... ♪♫ | **?** | TROLOLOLOLO... ♪♫ | +| sound037 | Blupi is crushed by a bulldozer | Au-aaa...! | AAAAa! | Aie | Aouuuu...! | **?** | Ajjj! | diff --git a/blupi.png b/blupi.png new file mode 100644 index 0000000..0924020 Binary files /dev/null and b/blupi.png differ diff --git a/cmake/FindArgagg.cmake b/cmake/FindArgagg.cmake new file mode 100644 index 0000000..210b655 --- /dev/null +++ b/cmake/FindArgagg.cmake @@ -0,0 +1,37 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#.rst: +# FindArgagg +# -------- +# +# Find the libargagg headers and libraries. +# +# This module reports information about the libargagg +# installation in several variables. General variables:: +# +# Argagg_FOUND - true if the libargagg headers and libraries were found +# Argagg_INCLUDE_DIRS - the directory containing the libargagg headers +# +# The following cache variables may also be set:: +# +# Argagg_INCLUDE_DIR - the directory containing the libargagg headers + + +# Based on FindIconv written by Roger Leigh + +# Find include directory +find_path(Argagg_INCLUDE_DIR + NAMES "argagg/argagg.hpp" + DOC "libargagg include directory") +mark_as_advanced(Argagg_INCLUDE_DIR) + +include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Argagg + FOUND_VAR Argagg_FOUND + REQUIRED_VARS Argagg_INCLUDE_DIR + FAIL_MESSAGE "Failed to find libargagg") + +if(Argagg_FOUND) + set(Argagg_INCLUDE_DIRS "${Argagg_INCLUDE_DIR}") +endif() diff --git a/cmake/FindIconv.cmake b/cmake/FindIconv.cmake new file mode 100644 index 0000000..ddbaacd --- /dev/null +++ b/cmake/FindIconv.cmake @@ -0,0 +1,49 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#.rst: +# FindIconv +# -------- +# +# Find the libiconv headers and libraries. +# +# This module reports information about the libiconv +# installation in several variables. General variables:: +# +# Iconv_FOUND - true if the libiconv headers and libraries were found +# Iconv_INCLUDE_DIRS - the directory containing the libiconv headers +# Iconv_LIBRARIES - libiconv libraries to be linked +# +# The following cache variables may also be set:: +# +# Iconv_INCLUDE_DIR - the directory containing the libiconv headers +# Iconv_LIBRARY - the libiconv library (if any) + + +# Written by Roger Leigh + +# Find include directory +find_path(Iconv_INCLUDE_DIR + NAMES "iconv.h" + DOC "libiconv include directory") +mark_as_advanced(Iconv_INCLUDE_DIR) + +# Find all Iconv libraries +find_library(Iconv_LIBRARY "iconv" + DOC "libiconv libraries)") +mark_as_advanced(Iconv_LIBRARY) + +include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Iconv + FOUND_VAR Iconv_FOUND + REQUIRED_VARS Iconv_INCLUDE_DIR + FAIL_MESSAGE "Failed to find libiconv") + +if(Iconv_FOUND) + set(Iconv_INCLUDE_DIRS "${Iconv_INCLUDE_DIR}") + if(Iconv_LIBRARY) + set(Iconv_LIBRARIES "${Iconv_LIBRARY}") + else() + unset(Iconv_LIBRARIES) + endif() +endif() diff --git a/cmake/FindSDLKitchensink.cmake b/cmake/FindSDLKitchensink.cmake new file mode 100644 index 0000000..06972cc --- /dev/null +++ b/cmake/FindSDLKitchensink.cmake @@ -0,0 +1,58 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#.rst: +# FindSDLKitchensink +# -------- +# +# Find the libsdlkitchensink headers and libraries. +# +# This module reports information about the libsdlkitchensink +# installation in several variables. General variables:: +# +# SDLKitchensink_FOUND - true if the libsdlkitchensink headers and libraries were found +# SDLKitchensink_INCLUDE_DIRS - the directory containing the libsdlkitchensink headers +# SDLKitchensink_LIBRARIES - libsdlkitchensink libraries to be linked +# +# The following cache variables may also be set:: +# +# SDLKitchensink_INCLUDE_DIR - the directory containing the libsdlkitchensink headers +# SDLKitchensink_LIBRARY - the libsdlkitchensink library (if any) + + +# Based on FindIconv written by Roger Leigh + +# Find include directory +find_path(SDLKitchensink_INCLUDE_DIR + NAMES "kitchensink/kitchensink.h" + DOC "libsdlkitchensink include directory") +mark_as_advanced(SDLKitchensink_INCLUDE_DIR) + +# Find all SDLKitchensink libraries +find_library(SDLKitchensink_LIBRARY + NAMES SDL_kitchensink + DOC "libsdlkitchensink libraries)") +find_library(SDLKitchensink_STATIC_LIBRARY + NAMES SDL_kitchensink_static + DOC "libsdlkitchensink static libraries)") +mark_as_advanced(SDLKitchensink_STATIC_LIBRARY) + +include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDLKitchensink + FOUND_VAR SDLKitchensink_FOUND + REQUIRED_VARS SDLKitchensink_INCLUDE_DIR + FAIL_MESSAGE "Failed to find libsdlkitchensink") + +if(SDLKitchensink_FOUND) + set(SDLKitchensink_INCLUDE_DIRS "${SDLKitchensink_INCLUDE_DIR}") + if(SDLKitchensink_LIBRARY) + set(SDLKitchensink_LIBRARIES "${SDLKitchensink_LIBRARY}") + else() + unset(SDLKitchensink_LIBRARIES) + endif() + if(SDLKitchensink_STATIC_LIBRARY) + set(SDLKitchensink_STATIC_LIBRARIES "${SDLKitchensink_STATIC_LIBRARY}") + else() + unset(SDLKitchensink_STATIC_LIBRARIES) + endif() +endif() diff --git a/cmake/LinuxAppImageBuild.cmake b/cmake/LinuxAppImageBuild.cmake new file mode 100644 index 0000000..4ebc588 --- /dev/null +++ b/cmake/LinuxAppImageBuild.cmake @@ -0,0 +1,154 @@ + +set (APPIMAGE_ASSISTANT_PROGRAM CACHE FILEPATH "AppImageAssistant executable") +set (APPIMAGE_APPRUN_PROGRAM CACHE FILEPATH "AppImage AppRun executable") + +set (APPIMAGE_WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/deploy/linux-appimage" CACHE PATH "Where to put the AppDir items") +set (APPIMAGE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/package/linux-appimage" CACHE PATH "AppImage output directory") +set (APPIMAGE_FOLLOW_STANDARD OFF CACHE BOOL "Whether generator should follow the spec") + +macro (APPIMAGE_PACKAGE TARGET APPIMAGE_TITLE APPIMAGE_DISPLAYNAME CONFIGDIR DATA LIBRARIES LIBRARY_FILES ICON_REF SIGN_APP) + string (TOLOWER "${APPIMAGE_TITLE}" APPIMAGE_INTERNALNAME) + string (MAKE_C_IDENTIFIER "${APPIMAGE_INTERNALNAME}" APPIMAGE_INTERNALNAME) + + # Some prerequisites + # TITLE here is used as the name of the final AppImage as well as the desktop entry's name + set (APPIMAGE_TITLE "${APPIMAGE_TITLE}") + set (APPIMAGE_DISPLAYNAME "${APPIMAGE_DISPLAYNAME}") + set (APPIMAGE_INTERNALNAME "${APPIMAGE_INTERNALNAME}") + set (APPIMAGE_LIBRARIES) + set (APPIMAGE_DATA) + set (APPIMAGE_CONFIG_DIR "${CONFIGDIR}") + set (APPIMAGE_DEFAULT_ICON_FILE "${APPIMAGE_CONFIG_DIR}/icon.svg") + + # Icon file to be used for the AppImage, only one in this case, preferrably SVG + set (APPIMAGE_ICON "${APPIMAGE_DEFAULT_ICON_FILE}") + # We define a way to reference this icon based on where it is located + set (APPIMAGE_ICON_REF "${ICON_REF}") + + # This helps the window manager to recognize the program even if it has no embedded or loaded icon + set (APPIMAGE_EXEC_WM ${TARGET}) + + # Sets the launch variable in .desktop entry + set (APPIMAGE_EXEC ${TARGET}) + + # This directory is used for temporary files, might get messy + set ( APPIMAGE_CACHE_DIR "${APPIMAGE_WORKING_DIRECTORY}/${APPIMAGE_INTERNALNAME}_cache") + # Where the AppDir is generated + set (APPIMAGE_INTERMEDIATE_DIR "${APPIMAGE_WORKING_DIRECTORY}/${APPIMAGE_INTERNALNAME}") + set (APPIMAGE_ICON_TARGET "${APPIMAGE_INTERMEDIATE_DIR}/${APPIMAGE_ICON_REF}") + set (APPIMAGE_BINARY_DIR "${APPIMAGE_INTERMEDIATE_DIR}/usr/bin") + set (APPIMAGE_ASSET_DIR "${APPIMAGE_INTERMEDIATE_DIR}/usr/share") + set (APPIMAGE_LIBRARY_DIR "${APPIMAGE_INTERMEDIATE_DIR}/usr/lib") + set (APPIMAGE_FINAL_NAME "${APPIMAGE_OUTPUT_DIRECTORY}/${APPIMAGE_TITLE}.AppImage") + + list (APPEND APPIMAGE_LIBRARIES ${LIBRARIES}) + list (APPEND APPIMAGE_DATA ${DATA}) + + # Remove the previous AppImage file to avoid confusion when generating a new one + add_custom_command ( + TARGET ${TARGET} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E remove "${APPIMAGE_FINAL_NAME}" + ) + + # Create some necessary directory structure in AppDir + add_custom_command ( + TARGET ${TARGET} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "${APPIMAGE_OUTPUT_DIRECTORY}" + ) + add_custom_command ( + TARGET ${TARGET} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "${APPIMAGE_BINARY_DIR}" + ) + add_custom_command ( + TARGET ${TARGET} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "${APPIMAGE_CACHE_DIR}" + ) + add_custom_command ( + TARGET ${TARGET} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "${APPIMAGE_LIBRARY_DIR}" + ) + add_custom_command ( + TARGET ${TARGET} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "${APPIMAGE_ASSET_DIR}" + ) + + # Copy and configure some data for the AppDir + configure_file ( + "${APPIMAGE_ICON}" + "${APPIMAGE_ICON_TARGET}.svg" + COPYONLY + ) + configure_file ( + "${APPIMAGE_ICON}" + "${APPIMAGE_INTERMEDIATE_DIR}/.DirIcon" + COPYONLY + ) + configure_file ( + "${APPIMAGE_CONFIG_DIR}/application.desktop.in" + "${APPIMAGE_INTERMEDIATE_DIR}/${APPIMAGE_INTERNALNAME}.desktop" + @ONLY + ) + configure_file ( + "${APPIMAGE_APPRUN_PROGRAM}" + "${APPIMAGE_INTERMEDIATE_DIR}/AppRun" + COPYONLY + ) + + # Copy resources into AppDir + foreach (RESC ${DATA}) + add_custom_command ( + TARGET ${TARGET} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory "${RESC}" "${APPIMAGE_ASSET_DIR}" + ) + endforeach () + + # Copy bundled libraries into AppDir + foreach (LIB ${LIBRARY_FILES}) + add_custom_command ( + TARGET ${TARGET} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy "${LIB}" "${APPIMAGE_LIBRARY_DIR}" + ) + endforeach () + + foreach (LIB ${LIBRARIES}) + add_custom_command ( + TARGET ${TARGET} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy "$" "${APPIMAGE_LIBRARY_DIR}" + ) + endforeach () + + # Copy the binary to AppDir + add_custom_command ( + TARGET ${TARGET} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy "$" "${APPIMAGE_BINARY_DIR}" + ) + + if (SIGN_APP) + set (APPIMGKITARGS "-s") + else () + set (APPIMGKITARGS "") + endif () + + # Do the actual packaging step with AppImageKit + add_custom_command ( + TARGET ${TARGET} + POST_BUILD + COMMAND "${APPIMAGE_ASSISTANT_PROGRAM}" "${APPIMGKITARGS}" "${APPIMAGE_INTERMEDIATE_DIR}" "${APPIMAGE_FINAL_NAME}" + ) + + install ( + FILES "${APPIMAGE_FINAL_NAME}" + DESTINATION "${CMAKE_PACKAGED_OUTPUT_PREFIX}/linux-appimage" + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE + ) +endmacro () diff --git a/cmake/Ronn2Man.cmake b/cmake/Ronn2Man.cmake new file mode 100644 index 0000000..b266b48 --- /dev/null +++ b/cmake/Ronn2Man.cmake @@ -0,0 +1,59 @@ +# +# Based on work of Emmanuel Roullit +# Copyright 2009, 2012 Emmanuel Roullit. +# Subject to the GPL, version 2. +# +MACRO(ADD_MANPAGE_TARGET) + # It is not possible add a dependency to target 'install' + # Run hard-coded 'make man' when 'make install' is invoked + INSTALL(CODE "EXECUTE_PROCESS(COMMAND make man)") + ADD_CUSTOM_TARGET(man) +ENDMACRO(ADD_MANPAGE_TARGET) + +FIND_PROGRAM(RONN ronn) +FIND_PROGRAM(GZIP gzip) + +IF (NOT RONN OR NOT GZIP) + IF (NOT RONN) + message(WARNING "ronn not found, manpages won't be generated") + ENDIF(NOT RONN) + IF (NOT GZIP) + message(WARNING "gzip not found, manpages won't be generated") + ENDIF(NOT GZIP) + # empty macro + MACRO(manpage MANFILE) + ENDMACRO(manpage) + SET (MANPAGES_SUPPORT FALSE) +ELSE (NOT RONN OR NOT GZIP) + MESSAGE (STATUS "Looking for ronn to generate manpages - found") + SET (MANPAGES_SUPPORT TRUE) + + MACRO(manpage RONNFILE SECTION) + SET(RONNFILE_FULL_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${RONNFILE}) + + ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION} + DEPENDS ${RONNFILE_FULL_PATH}.${SECTION}.ronn + COMMAND ${RONN} + ARGS -r --pipe ${RONNFILE_FULL_PATH}.${SECTION}.ronn + > ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION} + ) + + ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}.gz + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION} + COMMAND ${GZIP} -c ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION} + > ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}.gz + ) + + SET(MANPAGE_TARGET "man-${RONNFILE}") + + ADD_CUSTOM_TARGET(${MANPAGE_TARGET} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}.gz) + ADD_DEPENDENCIES(man ${MANPAGE_TARGET}) + + INSTALL( + FILES ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}.gz + DESTINATION share/man/man${SECTION} + ) + ENDMACRO(manpage RONNFILE SECTION) +ENDIF(NOT RONN OR NOT GZIP) diff --git a/planetblupi.6.ronn b/planetblupi.6.ronn new file mode 100644 index 0000000..d87626e --- /dev/null +++ b/planetblupi.6.ronn @@ -0,0 +1,211 @@ + +planetblupi(6) -- a delirious spell-binding game +================================================ + +## SYNOPSIS + +`planetblupi` [...] + +## DESCRIPTION + +**Planet Blupi** is a strategy and adventure game. It subtly blends action with +thought-provoking challenges. Behind the quiet and gentle facade, you'll enjoy +a fascinating diversion full of surprises. Planet Blupi is ideal for ages +12 to 99.. + +This version contains over 30 missions and a built in editor, which enables you +to construct your own missions. + +## CONFIGURATION + +**Planet Blupi** supports at least GNU/Linux 2.6.32, macOS 10.9 and Microsoft +Windows Vista. If your OS is not listed, maybe it's possible to build yourself +the game. Most Unix and Unix-like OS should be supported. + +For the video output, a 3D accelerated video card is highly recommended. It's +still possible to use pure software rendering in all other cases. + +For the sound card, any cards supported by ALSA, PulseAudio, macOS or +DirectSound should work fine. + +## SCREEN + +The game **Planet Blupi** runs in full screen by using your desktop resolution. +If you are encounting errors, you can start the game by default in windowed +mode. Proceed as follows: + +1. Quit the game **Planet Blupi**. +2. Open the file `share/planetblupi/data/config.json` with a text editor. +3. Replace `fullscreen: true` by `fullscreen: false`. +4. Save and restart the game. + +In this mode the screen is no more scrolled if the mouse touches the window +borders. Use the keyboard arrows instead. + +It's possible to start the game with `--fullscreen off` instead of editing +the `config.json` file. + +Another way is to start the game in legacy mode. With this mode, the game +runs with the original 640x480 resolution. Use `--legacy` on the command +line. + +If the problem persists, maybe you should try to start the game with the +software renderer. Edit the `config.json` file and add `"renderer": "software"` +or start the game with `--renderer software`. + +Another possibility exists. You can try to change the driver used by the +accelerated renderer. By default it uses `"direct3d"`, you can change by +`"opengl"` with `"driver": "opengl"` with the `config.json` file or +`--driver opengl` by command line argument. + +## MOUSE + +The left button is always used in three steps: + + 1. Select a Blupi. + 2. Click where you want him to act. + 3. Click the button corresponding to the required operation. + +If the chosen Blupi is already selected (blue or red circle around him), step 1) +is not necessary. + +You may select several Blupis by maintaining the Shift button +pressed. + +The right button is a shortcut. It orders the selected Blupi to do the most +useful operation on the selected spot. + +## KEYBOARD + + * Arrows: + Scrolls the visible part of the scene. + + * Spacebar: + Shows or hides items. + + * F1: + Describes the goal without interrupting the game. + + * F5: + Normal speed (x1). + + * F6: + Double speed (x2). + + * Home: + Returns to place of mission departure + + * Ctrl+F9..F12: + Bookmarks a spot. + + * F9..F12: + Returns to the corresponding bookmarked spot. + + * Pause: + Temporarily suspends the game (excepted with the hard difficulty). + +When you switch to another application, the game is automatically paused. + +## MUSIC + +The music is provided in *OGG* and *MIDI* formats. The *OGG* variant is preferred +because the render is the same for all platforms. For purist fanboys, it's +possible to enforce the *MIDI* variant by starting the game with the +`--restore-midi` command line argument. Note that in this case, it's possible +to lose some instruments, it depends of your system. + +You can edit the `share/planetblupi/data/config.json` file and add an entry +`"restoremidi": true`, or simply use the new settings available in the global +settings screen in the game. + +If you want, you can overload all musics with yours by providing *OGG* or *MIDI* +music files in your user directory. + +On Windows, type `%APPDATA%\Epsitec SA\Planet Blupi` in the file browser. +On macOS, look at `~/Library/Application Support/Epsitec SA/Planet Blupi`. +On Linux, look at `~/.local/share/Epsitec SA/Planet Blupi`. + +You can create a `music` sub-directory with your musics. For example: +`%LOCALAPPDATA%\Epsitec SA\Planet Blupi\music\music000.ogg`. + +Only 10 musics are supported: `music000` to `music009`. + +## OPTIONS + + * `-h`, `--help`: + Print this help message and exit. + + * `-V`, `--version`: + Print version and exit. + + * `-s`, `--speed-rate`: + Change the speed rate `[1;2]` (default: `1`). + + * `-t`, `--timer-interval`: + Set the timer interval (refresh). The default value is 50ms. This is an + advanced option because it changes the main events loop frequency. + + * `-f`, `--fullscreen`: + Load in fullscreen `[on;off]` (default: `on`). + + * `-z`, `--zoom`: + Change the window scale (only if fullscreen is `off`) `[1;2]` + (default: `1`). + + * `-l`, `--legacy`: + Start the game in legacy display mode (640x480). + + * `-r`, `--renderer`: + Set a renderer `[auto;software;accelerated]` (default: `auto`). Use the + `software` renderer if the `accelerated` renderer is bugged. Note that you + can try other drivers (option `-d`) before forcing the `software` renderer. + + * `-d`, `--driver`: + Set a driver `[auto;direct3d;direct3d11;opengl;opengles2;opengles]` + (default: `auto`, ignored with `software` renderer). + + * `-c`, `--enable-recorder`: + Enable the recorder feature (F3/F4). When playing, + you can start a record with F3 and stop with F4. + + * `-p`, `--play-record`: + Play a record generated by F3 (`--enable-recorder`). + + * `-b`, `--restore-bugs`: + Restore funny original bugs of older versions < v1.9. It can be very fun + and interesting for speedruns. + + **Tower rays:** with this bug, it's possible to add rays on a map even + without tower. It's possible only when building a new map. + + **Mine flag:** you can build a mine without prospecting if you know exactly + where is the flag case. + + **Enemy control**: you can take the enemy control by going in an enemy + factory while the door is open. + + **Duplicate everything**: this bug is very useful for duplicating objects + by sending the same order to two Blupis. + + **Take trapped ennemy**: it's possible to take a trapped enemy; it's useless + but possible. + + **Set fire**: you can add invisible fire on every type of cells (when + building a map). + + * `-m`, `--restore-midi`: + Restore playback based on MIDI music instead of OGG. + + * `-q`, `--render-quality`: + Enable anti-aliasing [on;off] (default: on, ignored if windowed). + +## AUTHOR + +**Planet Blupi** is an original creation of Epsitec SA. + +http://www.blupi.org + +## COPYRIGHT + +planetblupi is Copyright (C) 1997, Daniel Roux & EPSITEC SA and +Copyright (C) 2017-2018, Mathieu Schroeter diff --git a/resources/darwin/Info.plist.in b/resources/darwin/Info.plist.in new file mode 100644 index 0000000..05efeef --- /dev/null +++ b/resources/darwin/Info.plist.in @@ -0,0 +1,16 @@ + + + + + CFBundleVersion + @BUNDLE_VERSION@ + CFBundleIdentifier + @BUNDLE_IDENTIFIER@ + CFBundleDisplayName + @CPACK_BUNDLE_NAME@ + CFBundleExecutable + @CPACK_BUNDLE_NAME@ + CFBundleIconFile + @BUNDLE_ICON_REF@ + + diff --git a/resources/darwin/Planet Blupi b/resources/darwin/Planet Blupi new file mode 100755 index 0000000..d401e10 --- /dev/null +++ b/resources/darwin/Planet Blupi @@ -0,0 +1,2 @@ +#!/bin/sh +"$(dirname "$0")/../Resources/bin/planetblupi" $@ diff --git a/resources/darwin/background.png b/resources/darwin/background.png new file mode 100644 index 0000000..d16365d Binary files /dev/null and b/resources/darwin/background.png differ diff --git a/resources/darwin/background.svg b/resources/darwin/background.svg new file mode 100644 index 0000000..309a9b3 --- /dev/null +++ b/resources/darwin/background.svg @@ -0,0 +1,323 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + Planet Blupi + + diff --git a/resources/darwin/background.tiff b/resources/darwin/background.tiff new file mode 100644 index 0000000..68041f6 Binary files /dev/null and b/resources/darwin/background.tiff differ diff --git a/resources/darwin/background@2x.png b/resources/darwin/background@2x.png new file mode 100644 index 0000000..510bb1e Binary files /dev/null and b/resources/darwin/background@2x.png differ diff --git a/resources/darwin/dmgsetup.scpt b/resources/darwin/dmgsetup.scpt new file mode 100644 index 0000000..20c4773 --- /dev/null +++ b/resources/darwin/dmgsetup.scpt @@ -0,0 +1,57 @@ +on run argv + set image_name to item 1 of argv + + tell application "Finder" + tell disk image_name + + -- wait for the image to finish mounting + set open_attempts to 0 + repeat while open_attempts < 4 + try + open + delay 1 + set open_attempts to 5 + close + on error errStr number errorNumber + set open_attempts to open_attempts + 1 + delay 10 + end try + end repeat + delay 5 + + -- open the image the first time and save a DS_Store with just + -- background and icon setup + open + set current view of container window to icon view + set theViewOptions to the icon view options of container window + set background picture of theViewOptions to file ".background:background.tiff" + set arrangement of theViewOptions to not arranged + set icon size of theViewOptions to 128 + delay 5 + close + + -- next setup the position of the app and Applications symlink + -- plus hide all the window decoration + open + update without registering applications + tell container window + set sidebar width to 0 + set statusbar visible to false + set toolbar visible to false + set the bounds to { 400, 100, 900, 465 } + set position of item "Planet Blupi.app" to { 133, 200 } + set position of item "Applications" to { 378, 200 } + end tell + update without registering applications + delay 5 + close + + -- one last open and close so you can see everything looks correct + open + delay 5 + close + + end tell + delay 1 +end tell +end run diff --git a/resources/darwin/icon.icns b/resources/darwin/icon.icns new file mode 100644 index 0000000..ccf2c7b Binary files /dev/null and b/resources/darwin/icon.icns differ diff --git a/resources/data/config.json b/resources/data/config.json new file mode 100644 index 0000000..ed4fe9c --- /dev/null +++ b/resources/data/config.json @@ -0,0 +1,5 @@ +{ + "fullscreen": true, + "zoom": 1, + "speedrate": 1 +} diff --git a/resources/data/de/stories.blp b/resources/data/de/stories.blp new file mode 100644 index 0000000..049ded8 --- /dev/null +++ b/resources/data/de/stories.blp @@ -0,0 +1,1010 @@ +$1 +1|Ziel: +1| +1|Jeder Blupi muss in ein Haus +1|gelangen. +1|Benutze den linken Mausknopf. + + +2|1) Klicke auf einen Blupi. Ein blauer +2| Ring zeigt an, dass dieser Blupi +2| ausgewählt ist. +2| +2|2) Klicke auf ein Haus. +2| +2|3) Klicke auf den Knopf "Gehen" +2| +2|4) Wiederhole diesen Vorgang für +2| den anderen Blupi. + + + + + + + + + + Klicke auf den Würfel um + zu beginnen. + + +$2 +Die zweite Trainingsmission ist kaum +schwieriger: + +1|Transportiere die beiden Holzhaufen +1|auf die gestreiften Quadrate rechts. +1| +1|Zuvor muss Blupi jedoch Tomaten +1|essen, um genügend Kraft zu haben. +2|Du wirst bemerken dass der rote +2|Ring an Blupis Füssen blau wird. +2|Dieser Ring zeigt Blupis Energie- +2|reserve an: +2| +2| rot = müde +2| blau = voll in Form + + +Trick: + +Wenn du das Sichtfenster verschieben +willst, bringe entweder den Mauszeiger +an den Bildschirmrand oder benutze +die Pfeiltasten auf der Tastatur +deines Computers. + + +$3 +1|Finde die Eier ... +1| +1|Wenn Du diese auf einen Brutplatz legst, +1|schlüpfen nach kurzer Zeit vier neue +1|Blupis aus ! + + + +Trick: + +Wenn Du besonders schnell sein willst, +dann halte die Maus mit der rechten +Hand und drücke auf die Pfeiltasten +mit der linken Hand (oder umgekehrt). + +$4 +1|Ziel: +1| +1|Alle vier Blupis müssen die Häuser +1|auf den Inseln im Norden erreichen. + +2|Alle Blupis müssen zuerst essen, um +2|genügend Kraft zum Springen +2|zu haben. + +$5 +1|Ziel: +1| +1|Lege zwei Tomatenhaufen auf die +1|gestreiften Quadrate. +1| +1|Gehe folgendermassen vor: +1| +1|1) Fälle einen Baum + +2|2) Baue ein Gartenhäuschen +2| +2|3) Pflanze Tomaten an +2| +2|4) Lege die zwei Tomatenhaufen auf +2| die gestreiften Quadrate (aber +2| die Tomaten nicht essen). + +$6 +1|Ziel: +1| +1|Alle Blupis müssen eines der Häuser +1|auf einer kleinen Insel erreichen. +1| +1|Leider ist nur für einen Blupi +1|genügend Nahrung vorhanden. + +2|Produziere genügend Nahrung +2|für alle. + + +$7 + +$8 + +$9 + +$10 + +#h1 +Blupi lebt vergnügt auf seinem +Planeten, bis eines Tages ein +seltsamer Meteor einschlägt. + +Später entdeckt Blupi einen +gefährlichen Virus, der ihn mit +einer seltsamen Krankheit +ansteckt und dazu noch allerlei +Ungetüme, die ihm das Leben +schwer machen. + +#h2 +Was ist los ? + +Der Meteor ist in Wirklichkeit +ein Raumschiff, das einen ganz +speziellen Roboter transportiert. + +Dieser Roboter baut Fabriken und +Werkstätten, in denen Viren und +andere unangenehme Erscheinungen +produziert werden. + +Blupi muss jetzt den Reichtum +seines Planeten dazu benutzen, +die Eindringlinge wieder zu +vertreiben... + + +#1 +Die Landung des Raumschiffes hat +einen Brand entfacht. Blupis Dorf +ist bedroht ! + + +1|Ziel: +1| +1|Verhindere, dass Blupis Dorf +1|verbrennt. Dazu gibt es nur ein +1|Mittel: die Bäume in der Richtung +1|aus der das Feuer kommt fällen. + + + +2|Trick: +2| +2|Wenn Blupi von einem Baum ver- +2|deckt ist, kannst Du die Bäume +2|vorübergehend durchsichtig +2|machen, in dem Du auf die +2|Leertaste drückst. + + +@1 +1|Lösung: +1| +1|Befehle einem Blupi Bäume zu +1|fällen, und befehle den zwei +1|anderen Blupis die Bretter +1|abzutransportieren. + +#2 +1|Blupi hat sich verlaufen und +1|befindet sich auf einer Lichtung +1|weit von seinem Dorf entfernt. +1| +1|1) Baue ein Gartenhäuschen +1| und pflanze Tomaten an. + +2|2) Baue einen Brutplatz um +2| Verstärkung zu erhalten. +2| +2|3) Gebe den vier Blupis zu +2| essen und suche das Dorf. +2| +2| +2|Achtung: +2|Ein unvorhergesehenes Ereignis +2|wird eintreten. + +@2 +1|Hinweise: +1| +1|Baue zwei Palisaden, um die +1|Spinne daran zu hindern, die +1|Tomaten zu fressen. + +2|Die vier Häuser befinden sich +2|im Osten. + +#3 +1|Ziel: +1| +1|Verhindere, dass die zwei +1|Blupis verbrennen, indem Du +1|eine Mauer baust. + +2|Achtung: +2| +2|Der Moosuntergrund brennt +2|sehr gut... + + +@3 +1|Lösung: +1| +1|1) Bearbeite einen Felsen +1| +1| Die kleinen Felsen sind +1| schneller verarbeitet +1| als die grossen. + +2|2) Baue eine Mauer. +2| +2|3) Warte bis das Feuer +2| aus gegangen ist. + + +#4 +1|Ziel: +1| +1|Alle vier Blupis müssen die +1|gestreiften Quadrate erreichen. + +@4 +1|Lösung: +1| +1|1) Fälle einen Baum. +1| +1|2) Bringe die Bretter zum Ufer. +1| +1|3) Baue eine Brücke zu den +1| erschöpften Blupis. + +2|4) Und das gleiche noch drei mal. +2| +2|Die erschöpften Blupis können +2|nun die Brücke überqueren. + +#5 +1|Die Falle: +1|Achtung, der Boden wo die Blupis +1|gefangen sind ist brennbar, und +1|die Feuersbrunst kommt immer +1|näher. +1| +1|Ziel: +1|Alle Blupis müssen überleben, bis +1|das Feuer ausgegangen ist. + +2|Achtung: +2|Das Errichten einer Mauer ist so +2|anstrengend, dass der Blupi +2|danach stirbt ! + +Trick: +Wenn Du das Spiel zu langsam +findest, kannst Du es schneller +machen indem Du auf die Taste +F6 drückst. Mit F5 wird das +Spiel dann wieder langsamer. + +@5 +1|Hinweise: +1| +1|Du musst vier Mauern auf den +1|grauen Platten bauen. Dazu +1|musst Du zuerst zwei Bäume +1|fällen, und ein Gartenhäus- +1|chen sowie einen Brutplatz +1|bauen. + +2|Sobald die Mauern fertig sind, +2|musst Du warten bis das Feuer +2|ausgegangen ist. + +#6 +1|Ziel: +1| +1|Beschütze das Lager so schnell +1|wie möglich mit vier Wachtürmen. +1| +1|Du kannst dann die gestreiften +1|Quadrate im Osten erreichen. + + +2|Trick: +2|Du kannst mehrere Blupis auf +2|einmal auswählen, indem Du die +2|Umschalt Taste drückst, während +2|Du auf die Blupis klickst. + +@6 +1|Lösung: +1| +1|Befehle vier Blupis Felsen zu +1|bearbeiten (bei kleine Felsen +1|geht das schneller). +1| +1|Bringe die vier Steinhaufen zu +1|den vier grauen Platten und baue +1|dort vier Wachtürme. + +2|Warte nun auf die Ankunft und die +2|Zerstörung der Viren. +2| +2|Die vier verbleibenden Blupis +2|können nun die gestreiften +2|Quadrate im Osten erreichen. + +#7 +1|Ziel: +1| +1|Die vier Blupis müssen die +1|gestreiften Quadrate erreichen: +1| +1|Du musst Dich auch um den armen +1|isolierten Blupi kümmern. + + + +2|Achtung: +2| +2|Du kannst hier leider kein +2|Gartenhäuschen bauen. + +@7 +1|Lösung: +1| +1|Befehle einem der Blupis die +1|Tomaten zu nehmen, um diese +1|vor den Spinnen in Sicherheit +1|zubringen. +1| +1|Lass einen anderen Blupi auf die +1|Insel im Osten springen, und baue +1|eine Brücke in Richtung der +1|gestreiften Quadrate. + +2|Transportiere die Tomaten zu +2|dem isolierten Blupi und gib +2|sie ihm zu essen. Nun hat er +2|genügend Kraft um zu gehen. + +#8 +Ziel: + +1|Vermeide die Ansteckung von +1|einem oder zwei Blupis, und finde +1|die Arznei, um die Kranken +1|zu heilen. +1| +1|Am Schluss muss jeder Blupi in ein +1|Haus gelangen. + + +2|Hinweis: +2| +2|Baue ein Labor... + +@8 +1|Hinweise: +1| +1|Aus Steinen kannst Du ein Labor +1|bauen. Im Labor kannst Du dann +1|die gelben Blumen in Arznei +1|verwandeln. + +2|Baue dann eine Brücke, damit Du +2|den kranken Blupis die Arznei +2|bringen kannst. +2| +2|Die Häuser sind ganz im Osten. + + +#9 +1|Ziel: +1| +1|Finde heraus, wie Du die Eisbahn +1|überqueren kannst. + + +2|Blupi kann zwar ohne weiteres +2|auf Eis gehen, er verliert +2|dabei aber unheimlich viel +2|Kraft ! + +@9 +1|Hinweise: +1| +1|Baue zwei Wachtürme, um die +1|Spinnen abzuhalten. +1| +1|Baue dann ein Gartenhäuschen +1|und einen Brutplatz, um die +1|Eier auszubrüten. + +2|Da Blupi auf dem Eis sehr +2|viel Kraft verliert, muss +2|er die Tomaten direkt vor +2|der Eisbahn verspeisen. + +#10 +1|Ziel: +1| +1|Erreiche die Insel im Westen und +1|sprenge die Palisade. + +2|Führe dann vier Blupis auf die +2|gestreiften Quadrate. + +@10 +1|Hinweise: +1| +1|Baue eine Brücke zu den vier +1|gefangenen Blupis. Bearbeite +1|einen Felsen, bringe ihn in +1|die Nähe des Gartenhäuschens +1|und baue damit ein Labor. + +2|Die Blauen Blumen befinden sich +2|südöstlich. Du kannst Sie in +2|Dynamit verwandeln. + + +#11 +1|Ziel: +1| +1|Erreiche die Häuser im Norden. +1|Pass aber auf, denn sie sind +1|sehr gut bewacht. + +@11 +1|Hinweise: +1| +1|Baue eine Brücke zu der Insel +1|im Nordwesten, und fabriziere +1|mindestens vier +1|Dynamitladungen. + +2|Lege die Dynamitladungen in +2|die Nähe der Planierraupen, +2|aber nicht zu nahe. + + +#12 +1|Ziel: +1| +1|Drei Blupis müssen zu dem ver- +1|lassenen Blupi auf der Insel +1|im Westen gelangen. +1| + +@12 +1|Hinweise: +1| +1|Baue ein Gartenhäuschen und +1|pflanze Tomaten an. +1| +1|Mit den blauen Blumen im +1|Nordosten stellst Du +1|Dynamit her. + +2|Transportiere das Dynamit +2|bis zu der Insel weit im Westen. + + +#13 +1|Ziel: +1| +1|Entledige Dich der sechs Spinnen. +1|Die vier ersten sind einfache, aber +1|für die zwei letzten wird schon +1|etwas schwieriger. + + + +2|Trick: +2| +2|Finde heraus wie Du Gift im Labor +2|herstellen kannst. + + +@13 +1|Hinweise: +1| +1|Die vier ersten Spinnen kannst +1|Du fangen, indem Du mit Hilfe +1|der grünen Blumen Klebefallen +1|herstellst. Diese Fallen müssen +1|dann neben den Spinnen aufge- +1|stellt werden. + +2|Die beiden anderen kannst Du +2|vergiften, indem Du im Labor +2|Tomaten in Gift verwandelst. +2|Dazu musst Du allerdings erst +2|eine Brücke bauen, um die +2|Tomaten zum Labor bringen +2|zu können. + + +#14 +1|Ziel: +1| +1|Blupi muss nur zu seinem Haus +1|zurückfinden. + +@14 +1|Hinweise: +1| +1|Untersuche den Untergrund, da +1|wo sich die Kieselsteine +1|befinden, um Eisen zu finden. +1|Lege dann Bretter auf den +1|Wimpel und baue ein Bergwerk. +1| +1|Bearbeite einen Felsen, um eine +1|Werkstatt zu bauen. Dort kannst +1|Du dann das Eisenerz verarbeiten. + +2|Nimm die Zeitbombe und fahre +2|mit dem Jeep zu den Palisaden. +2|Sobald du dort ankommst, schalte +2|die Bombe ein und fahr so schnell +2|wie möglich weg. + + +#15 +1|Ziel: +1| +1|Ein einziger Blupi muss das Haus +1|im Norden erreichen. + +2|Du musst dazu zahlreiche +2|feindliche Einrichtungen +2|vernichten. + +@15 +1|Hinweise: +1| +1|Baue ein Gartenhäuschen und +1|zwei Wachtürme auf den grauen +1|Platten. +1| +1|Baue eine Brücke zur Insel im +1|Osten und bringe die verschie- +1|denen Blumen ins Lager. + +2|Baue ein Labor und produziere +2|Dynamit und Klebefallen. Schütze +2|das Lager innen mit Klebefallen +2|und aussen mit Dynamit. +2| +2|Sobald du glaubst, genügend Fallen +2|und Dynamit zu besitzen, schicke +2|einen Stosstrupp vor, um das +2|feindliche Lager zu zerstören. + +#16 +1|Zwei Blupis haben sich verlaufen. +1|Zeig ihnen, wie sie in Ihre Häuser +1|gelangen können. + + +@16 +1|Hinweise: +1| +1|Im Nordosten befindet sich ein +1|Bergwerk. Baue eine Werkstatt +1|und stelle eine Zeitbombe und +1|zwei Jeeps her. +1|Suche dann das feindliche Lager. + +2|Sprenge ein Loch in den Zaun um +2|das feindliche Lager und wenn +2|möglich sprenge dabei gleich- +2|zeitig die Planierraupen in die +2|Luft. +2| +2|Suche nun den Baum, fälle ihn +2|und baue eine Beammaschine. + +#17 +1|Ziel: +1| +1|Alle fünf Blupis müssen ein +1|Haus erreichen. + +2|Achtung, eines der Häuser befindet +2|sich hinter dem feindlichen Lager. + + +Trick: + +Du kannst mehrere Blupis auf +einmal auswählen, indem Du die +Umschalt Taste drückst, während +Du auf die Blupis klickst. + +@17 +1|Hinweise +1| +1|Ein Blupi kann sofort in das +1|Haus auf der Insel im Westen +1|gehen. Die vier anderen müssen +1|rasch vor den Planierraupen +1|weglaufen. + +2|Ziemlich weit im Norden befindet +2|sich das von Palisaden umgebene +2|Dorf. +2| +2|Nördlich des Dorfes befindet sich +2|eine Gegend reich an Eisen. +2| +2|Baue ein Boot, nimm eine Zeit- +2|bombe und fahre nach Norden... + +#18 +1|Beim Blumenpflücken hat sich +1|Blupi zu weit von zu Hause +1|entfernt und hat sich verlaufen. + + + +2|Hilf Blupi wieder nach Hause zu +2|finden. + +@18 +1|Hinweise: +1| +1|Baue ein Boot am Ufer des Sees +1|im Westen und lande auf der +1|anderen Seite der Mauer. + +2|Blupis Haus ist nun nicht mehr +2|weit. Du musst allerdings +2|den Planierraupen ausweichen. + +#19 +1| +1|Einige Planierraupen +1|terrorisieren Blupis Dorf. +1| +2| +2|Vernichte alle Planierraupen. + + +@19 +1|Hinweise: +1| +1|Baue Eisen ab und baue eine +1|Rüstung. Die Rüstung schützt +1|Blupi vor dem Feuer. +1| +1|Gehe nach Osten und baue ein +1|Boot. Suche eine Insel mit einem +1|Baum, fälle den Baum, transpor- +1|tiere die Bretter auf eine +2|grössere Insel und baue dort +2|eine Beammaschine, mit der Blupi +2|sich in ins innere des Lagers +2|beamen kann. +2| +2|Lege einige Dynamitstangen wo- +2|anders hin und sprenge ein Loch +2|in die Mauer. Mit den restlichen +2|Dynamitstangen kannst Du die +2|Planierraupen in die Luft sprengen + +#20 +1|Ziel: +1| +1|Zerstöre alle feindliche Gebäude. +1| + +@20 +1|Hinweise: +1| +1|Produziere ein Maximum an +1|Dynamit, Fallen, usw. und +1|sprenge dann den Zaun um +1|das feindliche Lager. + +#21 +1| +1|Der Roboter hält Blupi gefangen. +1| +1| +2| +2|Er muss sich befreien und sein +2|Haus wiederfinden. + +@21 +1|Hinweise: +1| +1|Lege das Dynamit in die Nähe +1|des Durchgangs durch die Felsen. +1|Lass die Planierraupe das Dyna- +1|mit zur Explosion bringen. + +2|Gehe dann Richtung Osten bis +2|zum Fluss und baue ein Boot. +2|Den zweiten Bretterstapel +2|brauchst Du um später ein +2|anderes Boot zu bauen. +2|Zuvor muss Du aber die Elek- +2|trisiermaschine mit der Klebe- +2|falle neutralisieren und eine +2|Zeitbombe bauen, um den Zaun +2|ganz im Osten zu zerstören. + +#22 +1|Ziel: +1| +1|1) Baue Boote. +1| +1|2) Erforsche alle Inseln. + +2|3) Vernichte alle +2| Feindeinrichtungen. + +@22 +1|Hinweise: +1| +1|Auf der Insel im Nordwesten gibt +1|es Eisenvorkommen. + +2|Auf der Insel im Osten gibt es +2|alles um Dynamit und Klebefalle +2|herzustellen. + +#23 +1| +1|Beim Beobachten des Roboters +1|hat sich Blupi verlaufen. +1| +2| +2|Bringe ihm Verstärkung und +2|vernichte alle Feinde. + + +@23 +1|Hinweise: +1| +1|Der isolierte Blupi muss sich +1|vom Roboter entfernen und zum +1|Holzdepot gelangen, um eine +1|Beammaschine zu bauen. + +2|Die zweite Gruppe muss ein Boot +2|bauen und die Bombe im Norden +2|finden, um damit den Zaun +2|weiter im Süden zu sprengen. +2|Nun kann ein Holzstapel zur +2|Insel gebracht werden und eine +2|Beammaschine kann gebaut +2|werden. + + +#24 +1| +1|Die Gegend ist voller Feinde. +1| +1| +2| +2|Ziel: +2| +2|Zerstöre alle Feinde. + +@24 +1|Hinweise: +1| +1|Lauf schnell nach rechts und +1|baue ein Boot. +1| +1|Im Inneren des Lagers findest +1|Du Eisen. + +2|Ganz im Norden des Lagers +2|neben dem kleinen See findest +2|Du Eier. + + +#25 +1|Seit einiger Zeit vermutet +1|Blupi die Existenz eines +1|geheimnisvollen Elements, +1|das von dem Roboter mitge- +1|bracht worden ist: +1| +1| das Platinium +1| +1|Dieses Element verhilft Blupi +1|zu einem ungeahnten techno- +1|logischen Fortschritt. + + +2|Ziel: +2| +2|Lege das Platinium auf die +2|gestreiften Quadrate. Es +2|befindet sich neben der Rakete. + +@25 +1|Hinweise: +1| +1|Neutralisiere die beiden Planier- +1|raupen mit Klebefallen. +1|Baue ein Boot im Norden des +1|feindlichen Lagers nehme eine +1|Zeitbombe und fahre Richtung +1|Osten. + +2|Finde einen Weg durch die +2|Felsen Richtung Süden. Das +2|feindliche Lager mit der Rakete +2|befindet sich ganz im Osten. + +#26 +1|Mit dem Platiniumwürfel erhält +1|Blupi Zugang zur Technologie +1|des Roboters. +1|Benutze es auf intelligente +1|Weise. + + +2|Ziel: +2| +2|Hilf Blupi sein Haus +2|wiederzufinden. + +@26 +1|Hinweise: +1| +1|Mit dem Platiniumwürfel kannst +1|Du in der Werkstatt einen +1|Roboter bauen. Baue ebenfalls +1|eine Zeitbombe. + +2|Steuere den Roboter durch das +2|feindliche Lager und sprenge +2|den Zaun in die Luft. Nehme +2|dann die Tomaten und gib sie +2|dem Blupi im Lager zu essen. +2|Lege die Tomaten direkt vor +2|die Eisbahn. + +#27 +1|Situation: +1| +1|Der Roboter besitzt die Unver- +1|schämtheit, seine Basis direkt +1|neben Blupis Dorf zu bauen. + + +2|Ziel: +2| +2|Erreiche das Feindliche Lager +2|und sprenge alles in +2|die Luft. + +@27 +1|Hinweise: +1| +1|Baue so schnell wie möglich +1|eine Beammaschine, mit der Du +1|zur Insel mit den Eiern gelangst. +1| +1|An den Stellen wo die Steinhaufen +1|liegen baue zwei Wachtürme. +1| +1|Baue dann links und rechts der +1|Türme Palisaden. + +2|Nun kannst Du aufatmen ! +2| +2|Du kannst das feindliche Lager +2|im Norden auf zwei verschiedene +2|Weisen erreichen: +2| +2|1) mit Booten +2|2) mit einer Brücke + + +#28 +1|Situation: +1| +1|Blupi hat versehentlich eine +1|Mauer rund um sein Haus gebaut. + + +2|Ziel: +2| +2|Blupi muss (nur ?) in sein +2|Haus gelangen. + +@28 +1|Hinweise: +1| +1|Auf der kleinen Insel im Norden +1|gibt es Eier. +1| +1|Durchquere das feindliche Lager +1|von Norden nach Süden und +1|pflücke die blauen Blumen. +1|Ein anderer Blupi kann sie dann +1|mit einem Boot holen und +1|Dynamit daraus machen. + + +#29 +1|Situation: +1| +1|Blupis Lebensraum wird mehr und +1|mehr durch den Roboter und seine +1|Schergen bedroht. + + +2|Ziel: +2| +2|Blupi muss zuerst ein gut +2|befestigtes Dorf bauen, um +2|dann zur Attacke überzugehen +2|und alle Feinde zu vernichten. + +@29 +1|Hinweise: +1| +1|Beschütze das Dorf mit Wach- +1|türmen. +1| +1|Lass die Bäume um die Pali- +1|saden in Ruhe, denn sie ver- +1|bessern die Abwehr gegen +1|springende Bomben. + +2|Benutze die grünen Blumen um +2|Klebefallen herzustellen. +2| +2|Im Südwesten kannst Du Eisen +2|abbauen und somit Bomben und +2|Rüstungen herstellen. + +#30 +1|Situation: +1| +1|Der Krieg hat nun lange genug +1|gedauert. Blupi hat mit dem +1|letzten überlebenden Roboter ein +1|Abkommen geschlossen. +1|Blupi muss ihm helfen zu seiner +1|Rakete zu gelangen. +1|Der Roboter verpflichtet sich +1|hingegen, Blupis Planeten für +1|immer zu verlassen. + + +2|Ziel: +2| +2|Bereite den Weg vor, so dass der +2|Roboter seine Rakete erreichen. +2|kann. +2|Der Roboter setzt sich erst dann +2|in Bewegung, wenn der Weg +2|fertig ist. + +@30 +1|Hinweise: +1| +1|Die Rakete befindet sich im +1|Südosten. +1| +1|Bahne Dir einen Weg durch die +1|Felsen. Baue ein Boot und fahre +1|zur Insel im Osten wo Du Eisen +1|finden kannst. + +2|Baue eine Werkstatt und mache +2|eine Bombe, mit der du den Zaun +2|um die Rakete in die Luft +2|sprengen kannst. +2| +2|Jetzt musst Du nur noch eine +2|Brücke bis zur Rakete bauen. diff --git a/resources/data/demo000.blp b/resources/data/demo000.blp new file mode 100644 index 0000000..53d34de Binary files /dev/null and b/resources/data/demo000.blp differ diff --git a/resources/data/demo001.blp b/resources/data/demo001.blp new file mode 100644 index 0000000..1897ded Binary files /dev/null and b/resources/data/demo001.blp differ diff --git a/resources/data/demo002.blp b/resources/data/demo002.blp new file mode 100644 index 0000000..e032298 Binary files /dev/null and b/resources/data/demo002.blp differ diff --git a/resources/data/demo003.blp b/resources/data/demo003.blp new file mode 100644 index 0000000..6dd78bb Binary files /dev/null and b/resources/data/demo003.blp differ diff --git a/resources/data/en/stories.blp b/resources/data/en/stories.blp new file mode 100644 index 0000000..728ec41 --- /dev/null +++ b/resources/data/en/stories.blp @@ -0,0 +1,1118 @@ +$1 +1|Goal: +1| +1|Each Blupi must enter a house. To +1|do so, always use the left button of +1|the mouse. + +2|1) Click on a Blupi +2| A blue ring will appear around +2| him indicating he is selected. +2| +2|2) Click on his house +2| +2|3) Click on the button "go" +2| +2|4) Repeat the operations for the +2| second Blupi. + + + + + + + + + + After having read these instructions + click on the dice below. + +$2 +Here is a second exercise a bit more +complicated: + +1|Transport both piles of planks on +1|the striped paving stones on +1|the right. +1| +1|Blupi must eat tomatoes to +1|gather enough strength for +1|this operation. Note that +2|when he eats, the red ring at +2|his feet turns blue. This +2|indicates his energy level. +2| +2| red = tired +2| blue = full shape + + + +Clue: +To scroll your screen, you may +draw your mouse to the side of +the screen or use the keyboard +arrows. + +$3 +1|Find the eggs ... +1| +1|By putting them on the +1|incubator, four new Blupis +1|will hatch. + + + + + + +Clue: +It is more efficient to +use the mouse in one hand +and use the other hand +for the keyboard arrows. + +$4 +1|Goal: +1| +1|The four Blupis must reach the +1|houses on the northern islands. + +2|Each Blupi must eat to have +2|enough strength to jump. + +$5 +1|Goal: +1| +1|Drop two batches of tomatoes +1|on the striped paving stones. + +2|To do so you must cut the trees +2|down, build a garden shed, grow +2|tomatoes and deposit two batches +2|of tomatoes on the striped paving +2|stones (do not eat them). + +$6 +1|Goal: +1| +1|Each Blupi must reach a house on +1|a small island. +1|Unfortunately there is only enough +1|food for one Blupi. +2|You will have to find a way of +2|producing enough food for all +2|of them. +2| +2|Fortunately, the island has. +2|lots of trees + +#h1 +Blupi is living quietly on his island +when a strange meteorite falls on +an arid region. + +It is only later that Blupi realizes +that his crops are always being +destroyed by huge spiders. + +Despite Blupi's excellent physical +condition, he now sneezes +and has caught a curious disease. + +#h2 +What is going on ? + +Well, the strange meteorite is in +fact a spaceship carrying a very +special robot. + +This robot builds factories which +produce enemies. + +Blupi must exploit all the natural +resources to get rid of these +intruders. + +#1 +The spaceship crash has set fire +to the forest. Blupi' village is +now threatened. + +1|Goal: +1| +1|Prevent the village from burning. +1|To do so, there is only one way: +1|Cut some trees down on the left. + + + + + + +2|Clue: +2| +2|If a Blupi is hidden by trees, +2|press space bar. Doing so will +2|render the trees temporarily +2|transparent. + +@1 +1|Solution: +1| +1|Order the Blupi on the left to +1|cut several trees down. The +1|two other Blupis will carry +1|the planks away. + +#2 +1|Situation: +1| +1|Blupi is far away from his village +1|and lost. He must organize himself +1|before going to look for his village. +1| +1|1) Build a garden shed and grow +1| tomatoes + +2|2) Build an incubator to obtain +2| support +2| +2|3) Feed the four Blupis and go and +2| find the village. +2| + + +2|Watch out: +2| +2|Something unusual is going to +2|happen. + + +@2 +1|Clues: +1| +1|First of, all you must build +1|two palisades in the north +1|to stop the spider from coming. +1|Only then will it be possible +2|to build a garden shed and +2|grow tomatoes in peace. +2| +2|To reach the four houses +2|you must go east. + + +#3 +1|Goal: +1| +1|Prevent the four lost Blupis from +1|burning. +1| +1|Finish the wall. + + + + +2|Watch out: +2| +2|The ground is made of moss +2|which burns very easily. + +@3 +1|Solution: +1| +1|1) Carve a rock. +1| Smaller rocks are quicker to +1| carve. + +2|2) Build a wall between the two +2| existing walls. +2| +2|3) Wait for the fire to stop. + +#4 +1|Goal: +1| +1|Make the four Blupis reach the +1|striped paving stones. + +@4 +1|Solution: +1| +1|1) Cut a tree down +1| +1|2) Carry the planks to the +1| water edge. +1| +1|3) Build a bridge towards the +1| two tired Blupis. + +2|4) Repeat this operation +2| three times. +2| +2|The tired Blupis may now +2|cross the bridge and reach +2|the striped paving stones. + +#5 +1|The trap: +1|Careful, the ground where the +1|Blupis are prisoners can easily +1|burn and fire is approaching. +1| +1|Goal: +1|Resist until the fire has +1|burnt out. + +2|Watch out: +2|Building a wall is a very +2|exhausting job for Blupi. Once +2|finished, he will die ! + + + +Clue: +If the game does not run fast +enough for you, press key F6 +to speed it up. F5 runs the +game at it's normal speed. + +@5 +1|Clues: +1| +1|You must build four walls on +1|the gray paving stones. You +1|will have to cut down two +1|trees to build a garden +1|shed and an incubator. + +2|When the walls are finished, +2|you will have to wait until +2|the fire comes and stops. + +#6 +1|Goal: +1| +1|A danger is present: protect +1|the camp as fast as possible +1|with four towers. + +2|You will be able to join the +2|striped paving stones in +2|the south-east. + + + + + + + + + +Clue: + +You may select several Blupis at +the same time by maintaining +the shift key pressed while +clicking on each Blupi. + + +@6 +1|Solution: +1| +1|You must ask four Blupis to +1|quickly carve a rock each. +1|The small rocks are easier +1|to carve. +1| +1|Transport the four piles of +1|stones onto the gray paving +1|stones and start building +1|protection towers. + +2|Wait for the arrival and +2|destruction of the viruses. +2| +2|The other four Blupis can +2|quietly go to the striped +2|paving stones in the +2|south-east. + +#7 +1|Goal: +1| +1|The four Blupis must reach +1|the striped paving stones. +1|You shall have to take care +1|of the farthest Blupi. + + + + + +2|Watch out: +2| +2|The ground is inappropriate +2|for building a garden shed. + +@7 +1|Solution: +1| +1|Ask a Blupi to remove the +1|tomatoes so that the spiders +1|cannot eat them. +1| +1|With another Blupi, jump on +1|the eastern island, build a +1|bridge that will join it to +1|the striped paving stones. + +2|Carry the tomatoes +2|towards the tired Blupi so +2|he can eat them. + +#8 +1|Goal: +1| +1|Avoid one or two Blupis from +1|being contaminated and find a +1|remedy for the sick ones. +1| +1|Finally each Blupi must enter +1|a house. + + + + + + + +2|Clue: +2| +2|Construct a laboratory. + +@8 +1|Clues: +1| +1|A laboratory must be made of +1|stones. It will enable you to +1|transform the yellow flowers +1|into a remedy for the sick +1|Blupis. + +2|You will have to build a bridge +2|to bring the remedy to the sick +2|Blupis. +2| +2|The houses are in the south-east. + +#9 +1|Goal: +1| +1|Find a way to cross the ice rink. +1| + + + + + + +2|Note: +2| +2|Blupi can walk on ice. However +2|the ice being slippery, he will +2|loose a lot of strength. + +@9 +1|Clues: +1| +1|Two towers will have to be built +1|to protect the Blupis from the +1|spiders. +1| +1|You will have to build +1|a garden shed and an incubator +1|in order to let the eggs hatch. + +2|Blupi loses a lot of strength +2|when he crosses the ice rink. +2|Therefore, you must bring him +2|tomatoes before he crosses. + +#10 +1|Goal: +1| +1|Reach the island in the +1|north-west and blow the +1|palisade up. + +2|All you have to do now is +2|to place four Blupis on the +2|striped paving stones. + +@10 +1|Clues: +1| +1|Build a bridge in the direction of +1|the four prisoners. This enables +1|you to carve a rock that shall +1|be taken to the garden shed to +1|build a laboratory. +1| +1|The blue flowers are in the +1|south-east. Thanks to the +1|laboratory they can be +1|transformed into dynamite. + +2|Use the dynamite to destroy +2|the palisade which is holding +2|the four Blupis prisoners. +2| +2|First of all, you will have to +2|draw back the prisoners to +2|protect them from the explosion. + +#11 +1|Goal: +1| +1|Reach the houses in the +1|north-east. Be careful, +1|they are well guarded. + +@11 +1|Clues: +1| +1|Build a bridge towards the +1|north-west island and then +1|make at least four packs +1|of dynamite. + +2|Drop the dynamite in the +2|north fairly close the +2|bulldozers. +2| +2|As long as the dynamite is +2|not made, avoid going north +2|or you will attract the +2|bulldozers. + +#12 +1|Goal: +1| +1|Three Blupis must join the +1|isolated Blupi on an island +1|in the north-west. + +@12 +1|Clues: +1| +1|Build a garden shed and grow +1|tomatoes. +1| +1|Make dynamite with the blue +1|flowers that can be found in +1|the north-east. + +2|Transport the dynamite to the +2|island situated in the west. +2| +2|Be careful, the way there +2|hides two viruses. + +#13 +1|Goal: +1| +1|Get rid of the six spiders. +1| +1|The first four it will be +1|easy. The two remaining +1|will be more difficult. + + + + + + +2|Clue: +2| +2|Find out how to produce poison +2|in the laboratory. + +@13 +1|Clues: +1| +1|The first four spiders will be +1|caught with traps made from +1|the green flowers in the +1|laboratory. +1| +1|The traps must be placed close to +1|the spiders. + +2|The two last ones will be +2|poisoned with the tomatoes +2|that have been altered +2|in the laboratory. +2| +2|Build a bridge to carry +2|the tomatoes to the laboratory. + +#14 +1|Goal: +1| +1|Blupi must simply go home. +1| + +@14 +1|Clues: +1| +1|Prospect for iron under the +1|small pebbles. Drop the planks +1|on the flag and build a mine. +1| +1|Carve a rock to build a +1|workshop so that you can use +1|the iron. + +2|Take a bomb, jump into the +2|jeep and go east. The jeep +2|will protect you from the +2|bulldozers. +2| +2|When you will get to the +2|palisade, you must leave the +2|jeep quickly, drop the time +2|bomb, switch it on, get back +2|into the jeep and buzz off. + +#15 +1|Goal: +1| +1|Only one Blupi must reach +1|the house in the north-east. + +2|To do so, you must destroy +2|the numerous enemy +2|installations. + +@15 +1|Clues: +1| +1|Build a garden shed and two +1|protection towers on the gray +1|paving stones. +1| +1|Build a bridge to join the is- +1|land in the east. Pick different +1|sorts of flowers and bring them +1|back to base camp. + +2|Build a laboratory, make +2|dynamite and sticky traps. +2|Protect the camp from the inside +2|with the sticky traps and the +2|outside, with the dynamite. +2| +2|When you think you have +2|enough dynamite and traps, send +2|a small commando to the north- +2|east to destroy the enemy camp. + +#16 +1|Situation: +1| +1|Blupi is lost in an arid part of +1|his planet with no trees. + + + + +2|Goal: +2| +2|The two Blupis must go back +2|home to their village. + +@16 +1|Clues: +1| +1|Find the mine in the north-east, +1|carve a rock to build a +1|workshop, make a time bomb +1|and two jeeps, and seek the +1|enemy camp in the south-west. + +2|Blow up the barrier protecting +2|the enemy camp. Try to blow +2|up the bulldozer as well. +2| +2|Go south and look for the only +2|tree and make a teleporter. + +#17 +1|Goal: +1| +1|The five Blupis must reach +1|a house. + +2|Careful, one house is +2|behind the enemy camp. + + + + + + + + + + + + +Clue: + +You may select several Blupis +at the same time by maintaining +the Shift key pressed while +clicking on each Blupi. + +@17 +1|Clues: +1| +1|A Blupi can now go to the house +1|on the western side of the island. +1|The four others must leave very +1|quickly because of the bulldozers. +1|The Blupis must go north-east. + +2|Further north-east, you will join +2|a village surrounded by palisades. +2| +2|North of the village, there is a +2|lot of iron. +2| +2|Make a boat and go north-east +2|witha time bomb. + +#18 +1|Situation: +1| +1|While Blupi was collecting +1|flowers, he did not realize +1|that he was far away from +1|his home. He is now lost in +1|a region full of enemies. + + + + + +2|Goal: +2| +2|Blupi must flee and find a +2|way of getting home. + +@18 +1|Clues: +1| +1|Find the water stretch to the +1|west. Make a boat. Be careful, +1|a lot of viruses are crawling +1|around. + +2|With the boat, you can cross +2|the wall and disembark on the +2|riverbank. +2| +2|Home is not so far now. Be +2|careful you must avoid the +2|bulldozers. + +#19 +1|Situation: +1| +1|Four bulldozers are threatening +1|Blupi's village. + + + + + +2|Goal: +2| +2|Destroy the bulldozers + +@19 +1|Clues: +1| +1|Ask a Blupi to extract iron +1|and build an armour. It will +1|protect him from the fire. +1| +1|Go east and build a boat. +1|Embark and look for another +1|island with a tree. Cut the +1|tree down and put the wood +2|on a bigger island. Make a +2|teleporter. It will bring you +2|to the armoury. +2| +2|Put some dynamite near the +2|surrounding wall and blow it +2|up. With the rest of the +2|dynamite, you can destroy +2|the bulldozers. + +#20 +1|Goal: +1| +1|Destroy all enemy installations. +1| + +@20 +1|Clues: +1| +1|Produce as much dynamite, +1|traps, etc. as possible before +1|blowing up the barriers that +1|protect the enemy camp. + +#21 +1|Situation: +1| +1|Blupi has been captured by +1|a nasty robot. He is held +1|prisoner in the robot's +1|base camp. + + + + +2|Goal: +2| +2|Blupi must escape and find +2|his house. + +@21 +1|Clues: +1| +1|Take the dynamite from the +1|northeast. Place it next to a +1|blue barrier facing a gap in the +1|rocks. The bulldozer will come +1|and make the dynamite explode. +1|This will destroy the barrier. + +2|Run to the east until you reach +2|the river. Make a boat with the +2|planks. You will need the second +2|pile of planks to build a boat +2|later. Before doing so, you will +2|have to catch the electrocutor +2|with the sticky trap and make a +2|time bomb in order to destroy +2|the blue barrier in the east. + +#22 +1|Goals: +1| +1|1) Make boats. +1| +1|2) Explore all the islands. +1| +1|3) Destroy all enemy installations. + +@22 +1|Clues: +1| +1|The island in the north-east +1|has a lot of iron. + +2|The island to the east has +2|all that is required to make +2|dynamite and sticky traps. + +#23 +1|Situation: +1| +1|Blupi is very curious: after +1|having observed the robot +1|for so long, he now realizes +1|that he has lost himself. + + + + + +2|Goal: +2| +2|Bring in support and destroy +2|the enemy ! + + +@23 +1|Clues: +1| +1|The isolated Blupi must go +1|away from the robot and go +1|west. Blupi must carve a +1|rock to be able to reachthe +1|wood, and then make a +1|teleporter. + +2|With a second group of Blupis, +2|you must make a boat, find the +2|bomb in the north-east and +2|blow up the barrier in the +2|south. This will enable you +2|to bring the wood onto the +2|departure island in order +2|to make a teleporter enabling +2|you to join and help the lost +2|Blupi. + +#24 +1|Situation: +1| +1|The region is full of enemies. +1| + + + +2|Goal: +2| +2|Destroy all enemies. + +@24 +1|Clues: +1| +1|Go south-east to avoid the +1|fire and make a boat with +1|the only tree left. +1| +1|In the camp, you will find +1|some iron. + +2|North of the camp, you will +2|find some eggs. + +#25 +1|Blupi has been suspecting +1|that the robot brought +1|something strange on his +1|planet: +1| +1| Platinium.... +1| +1|The platinium, which is placed +2|next to the robot's rocket, +2|will give him access to enemy +2|technology. +2| + + +2|Goal: +2|Bring a cube of platinum onto +2|the striped paving stones. + +@25 +1|Clues: +1| +1|Destroy the two bulldozers with +1|the sticky traps. Make a boat in +1|the north of the first enemy +1|camp, then embark with a time +1|bomb and go east. +1| +1|Look for a path between the +1|rocks going southwards. The +2|enemy camp with the rocket +2|is far in the east. You will +2|have to blow up a barrier to +2|be able to get hold of the +2|platinium. +2| +2|Bring the platinium back to +2|base camp. + +#26 +1|The cube of Platinum will give +1|you access to enemy technology +1|so use it correctly. + + + + + +2|Goal: +2| +2|Help Blupi find his house. + +@26 +1|Clues: +1| +1|Make a helping robot with the +1|cube of platinum in the factory +1|and make a time bomb. +1| +1|Take the robot and the bomb. +1|The robot can cross the western +1|enemy camp without being +2|noticed. Blow up the barrier +2|in the north and take the +2|tomatoes to feed the Blupi +2|in the base camp. +2| +2|Put the tomatoes down before +2|the first jump. + +#27 +1|Situation: +1| +1|The robot has had the cheek +1|to install his village nearby +1|Blupi's village. + + + + +2|Goal: +2| +2|Reach enemy camp and +2|destroy everything. + +@27 +1|Clues: +1| +1|Make a teleporter as fast as +1|possible so that you reach +1|the island with the eggs. +1|Build two protection towers +1|where the piles of stones +1|are. Build palisades on the +1|left and on the right of +1|each tower. + +2|Now you can breathe ! +2| +2|You have to ways of reaching +2|the enemy camp in the north, +2|either by boat or by +2|building a bridge. +2| +2|Up to you to choose ! + +#28 +1|Situation: +1| +1|Whilst building his house, +1|Blupi made a mistake: +1|he built a wall around it. + + + + + +2|Goal: +2| +2|Blupi must simply go home. + +@28 +1|Clues: +1| +1|A small island in the north +1|has a lot of eggs. +1| +1|You will have to cross the +1|enemy camp very quickly +1|in order to avoid the +1|bulldozers coming from the +1|north and from the south, +2|so that you can pick the +2|blue flowers. +2|Another Blupi can take them +2|away to make dynamite. +2| +2|The only rocks that can be +2|used are south of the enemy +2|camp, just outside the +2|protection wall. + +#29 +1|Situation: +1| +1|The free space is being more +1|and more occupied by the robot +1|and his acolytes. + + + + + +2|Goal: +2| +2|Blupi must build his village +2|and work out good defense +2|tactics. +2| +2|He will then attack and +2|eliminate all of his enemies. + +@29 +1|Clues: +1| +1|He must build protection towers +1|on the north-west side, on the +1|north-east side and on the +1|south-east side. All the rocks +1|are in the north-west. +1| +1|Do not cut the trees near the +1|palisades. They can be useful +1|against the jumping bombs ! + +2|The green flowers in the east +2|enable you to make sticky traps +2|to defend the village. +2| +2|Extract iron in the south-west +2|and make bombs and armours. + +#30 +1|Situation: +1| +1|This war can no longer last. +1|Blupi and the last robot have +1|come to an agreement: +1|He will help the robot back to +1|his rocket and, in return, +1|the robot will definitively +1|leave Blupi's planet. + + + + +2|Goal: +2| +2|Prepare the path to the rocket +2|so that the robot can leave +2|the planet. Having lost the +2|battle, the robot is angry so +2|he refuses to move until the +2|path is finished. + +@30 +1|Clues: +1| +1|Carve a rock in the southeast. +1|Cut a tree down and make a +1|boat. With the boat, look +1|for an island in the north-east. +1|Look for some iron, build a +1|mine and a factory. Make a +2|bomb that will enable you to +2|blow up the barriers around +2|the robot. +2| +2|All you have to do is to build +2|a bridge so that the robot can +2|go back into his rocket. diff --git a/resources/data/fr/stories.blp b/resources/data/fr/stories.blp new file mode 100644 index 0000000..107f2bc --- /dev/null +++ b/resources/data/fr/stories.blp @@ -0,0 +1,1180 @@ +$1 +1|Objectif : +1| +1|Chaque Blupi doit entrer dans une +1|maison. Pour cela, utilise toujours +1|le bouton principal de la souris +1|(généralement celui de gauche). + +2|1) Clique sur un Blupi. Un anneau bleu +2| apparaît à ses pieds pour indiquer +2| qu'il est sélectionné. +2| +2|2) Clique dans une maison. +2| +2|3) Clique dans le bouton "va". +2| +2|4) Répète les opérations pour le +2| deuxième Blupi. + + + + + + + + + Après avoir lu ces instructions, + clique sur le dé ci-dessous. + +$2 +Voilà un deuxième exercice, à peine +plus compliqué : + +1|Il suffit de transporter les deux tas +1|de bois sur les dalles hachurées situées +1|à l'est ... +1| +1|Avant cela, Blupi doit manger des +1|tomates pour avoir la force nécessaire. +2|Tu remarqueras que lorsqu'il mange, +2|l'anneau rouge à ses pieds devient bleu. +2|Cet anneau indique son niveau d'énergie : +2| +2| rouge = fatigué +2| bleu = pleine forme + + + + +Astuce : +Pour déplacer la partie visible, tu peux +amener la souris dans le bord de l'écran, +ou utiliser les touches flèches du +clavier. + +$3 +1|Trouve les oeufs ... +1| +1|En les déposant sur une couveuse, +1|tu pourras alors faire éclore +1|quatre Blupi tout neufs ! + + + + + +Astuce : +Tu seras particulièrement efficace en +tenant la souris dans la main droite, +et en actionnant les touches flèches +du clavier avec la main gauche ! + +$4 +1|Objectif : +1| +1|Les quatre Blupi doivent atteindre +1|les maisons situées sur d'autres îles +1|au nord-est. + +2|Chaque Blupi doit manger pour avoir +2|la force de sauter ! + +$5 +1|Objectif : +1| +1|Déposer deux lots de tomates sur les +1|dalles hachurées. Pour cela, il faut : +1| +1|1) Abattre le massif d'arbres. + +2|2) Construire une cabane de jardin. +2| +2|3) Cultiver des tomates. +2| +2|4) Déposer deux lots de tomates sur les +2| dalles hachurées (sans les manger). + +$6 +1|Objectif : +1| +1|Chaque Blupi doit atteindre une +1|maison sur une petite île. +1| +1|Malheureusement, la nourriture +1|présente ne suffit que pour un +1|seul Blupi ! + +2|Il faudra donc trouver le moyen de +2|produire de la nourriture pour tous. +2|Heureusement, l'île possède +2|un massif d'arbres ... + +$7 + +$8 + +$9 + +$10 + +#h1 +Blupi vit tranquillement sur sa +planète jusqu'à l'arrivée d'une +étrange météorite qui tombe dans +une région désertique. +Ce n'est que bien plus tard que +Blupi s'aperçoit que ses cultures +sont saccagées par de grosses +araignées. + +Alors que Blupi a toujours joui +d'une santé de fer, il lui arrive +maintenant d'éternuer et +d'attraper une curieuse maladie. + +#h2 +Que se passe-t-il ? + +Eh bien, l'étrange météorite +est en fait un vaisseau spatial +qui transporte un robot très +spécial. + +En effet, celui-ci construit des +usines, qui produisent à leur tour +différents ennemis. Blupi doit +dès lors exploiter à fond les +ressources de sa planète pour +parvenir à chasser ces intrus ... + + +#1 +La chute du vaisseau spatial a +mis le feu à la forêt, au loin. +Le village de Blupi est menacé ! + + +1|Objectif : +1| +1|Empêcher les maisons du village +1|de brûler. Pour cela, un seul +1|moyen: abattre des arbres à +1|l'ouest, pour stopper le feu ... + + + + + + +2|Astuce : +2| +2|Si un Blupi est caché par des +2|arbres, appuie sur la barre +2|d'espace pour rendre +2|temporairement les arbres +2|transparents. + +@1 +1|Solution : +1| +1|Ordonner au Blupi de gauche +1|d'abattre DES arbres un peu +1|plus à l'ouest. + +2|Les deux autres Blupi vont +2|transporter les planches ainsi +2|obtenues au sud, au fur et +2|à mesure. +2| +2|Elles seront ainsi hors +2|d'atteinte du feu ! + +#2 +1|Situation : +1| +1|Blupi est perdu dans une clairière +1|loin de son village. Il doit s'organiser +1|sur place avant de retrouver son +1|village. +1| +1|1) Construire une cabane de jardin +1| et cultiver des tomates. + +2|2) Construire une couveuse pour +2| obtenir du renfort. +2| +2|3) Nourrir quatre Blupi et partir +2| à la recherche du village ... +2| + + +2|Attention : +2| +2|Un événement imprévu viendra +2|perturber cette séquence ! + +@2 +1|Indices : +1| +1|Il faut d'abord construire +1|deux palissades au nord, +1|sur le sol improductif, pour +1|bloquer l'araignée. +2|Il sera alors possible de +2|construire une cabane de +2|jardin et de cultiver des +2|tomates en paix. +2| +2|Pour atteindre les quatre +2|maisons, il faut chercher +2|en direction de l'est ... + +#3 +1|Objectif : +1| +1|Empêcher les quatre Blupi perdus +1|dans la forêt de périr carbonisés. +1| +1|Pour cela, il faut terminer la +1|construction du mur de +1|protection. + + + +2|Attention : +2| +2|Lorsque le sol est constitué +2|de mousse, il brûle +2|merveilleusement bien ... + +@3 +1|Solution : +1| +1|1) Tailler un rocher. +1| +1| Les petits rochers sont +1| plus rapidement taillés ! + +2|2) Construire un mur entre +2| les deux murs existants. +2| +2|3) Attendre l'extinction +2| du feu ... + +#4 +1|Objectif : +1| +1|Permettre aux quatre Blupi +1|d'atteindre les dalles +1|hachurées. + +@4 +1|Solution : +1| +1|1) Abattre un arbre. +1| +1|2) Transporter les planches au +1| bord de l'eau. +1| +1|3) Construire un pont en direction +1| des deux Blupi fatigués. + +2|4) Répéter le tout trois fois ... +2| +2|Les Blupi fatigués peuvent alors +2|traverser le pont et atteindre +2|les dalles hachurées. + +#5 +1|Le piège : +1|Attention, le sol où sont prisonniers +1|les Blupi est très inflammable, +1|et le feu approche ... +1| +1|Objectif : +1|Résister jusqu'à l'extinction +1|du feu. + +2|Attention : +2|La construction d'un mur est un +2|travail épuisant. Il est inévitable +2|que Blupi meure lorsqu'il a terminé +2|un mur ! + + + +Astuce : +Si le jeu se déroule trop lentement +à ton goût, appuie sur la touche F6 +pour l'accélérer. Un pression sur F5 +rétablit la vitesse normale. + +@5 +1|Indices : +1| +1|Il s'agit de construire quatre murs +1|sur les dalles grises. Pour cela, +1|il faudra abattre les deux massifs +1|d'arbres disponibles puis construire +1|une cabane de jardin et une +1|couveuse. + +2|Lorsque les murs seront terminés, +2|il faudra patienter jusqu'à +2|l'arrivée, puis l'extinction +2|du feu ... + +#6 +1|Objectif : +1| +1|Protège le plus rapidement +1|possible le camp retranché +1|par 4 tours, car le danger +1|approche ... + +2|Tu pourras ensuite rejoindre +2|les dalles hachurées au +2|sud-est. + + + + + + + + + +Astuce : +Il est possible de sélectionner +plusieurs Blupi simultanément +en maintenant la touche Maj +enfoncée tout en cliquant sur +les Blupi. + +@6 +1|Solution : +1| +1|Il faut demander rapidement à +1|quatre Blupi de tailler chacun +1|un rocher. Les petits rochers +1|sont plus rapidement creusés ! +1| +1|Transporter les quatre tas de +1|pierres ainsi obtenus sur les +1|dalles grises puis construire +1|des tours de protection. + +2|Attendre l'arrivée et la +2|destruction des virus. +2| +2|Les quatre Blupi restants +2|peuvent alors tranquillement +2|aller vers les dalles hachurées +2|au sud-est. + +#7 +1|Objectif : +1| +1|Les quatre Blupi doivent atteindre +1|les dalles hachurées. +1| +1|Il faudra prendre soin du pauvre +1|Blupi éloigné ... + + + + +2|Attention : +2| +2|Le terrain ne permet pas de +2|construire une cabane de +2|jardin ! + +@7 +1|Solution : +1| +1|Demander à un Blupi de prendre +1|des tomates, pour les sauver des +1|araignées dévoreuses. +1| +1|Avec un autre Blupi, sauter sur +1|l'île à l'est, puis construire +1|un pont en direction des dalles +1|hachurées. + +2|Transporter les tomates vers +2|le Blupi fatigué, qui pourra +2|ainsi se nourrir puis se +2|déplacer. + +#8 +1|Objectif : +1| +1|Essaie d'éviter la contamination +1|à un ou deux Blupi, puis trouve +1|le remède pour les malades ... +1| +1|Finalement, chaque Blupi devra +1|entrer dans une maison. + + + + + + +2|Indice : +2| +2|Construis un laboratoire ... + +@8 +1|Indices : +1| +1|Il faut construire un laboratoire +1|avec des pierres. Il permettra +1|ensuite de transformer les fleurs +1|jaunes en une potion qui guérit +1|les malades. + +2|Il faudra construire un pont +2|pour apporter les bouteilles +2|de potion aux malades. +2| +2|Les maisons sont situées +2|au sud-est ... + +#9 +1|Objectif : +1| +1|Trouve le moyen de franchir +1|la patinoire glacée et +1|glissante ... + + + + + + +2|Remarque : +2| +2|Blupi peut marcher sur la glace. +2|Le seul problème vient de ce +2|qu'il glisse beaucoup, et perd +2|ainsi énormément de force ! + +@9 +1|Indices : +1| +1|Il faut construire deux tours +1|pour se protéger contre les +1|araignées. +1| +1|Ensuite, il faut construire une +1|cabane de jardin et une couveuse, +1|puis faire éclore les oeufs. + +2|Blupi perd énormément de force +2|lorsqu'il traverse une patinoire +2|de glace. Il faut donc amener +2|des tomates juste avant la +2|patinoire, pour que Blupi puisse +2|manger avant de la traverser ! + +#10 +1|Objectif : +1| +1|Atteindre l'île au nord-ouest, +1|puis faire sauter la palissade. + +2|Il ne reste alors plus qu'à placer +2|4 Blupi sur les dalles hachurées ... + +@10 +1|Indices : +1| +1|Il faut construire un pont en +1|direction des quatre prisonniers. +1|Ceci permet de tailler un +1|rocher qu'il faut ramener vers la +1|cabane de jardin, pour construire +1|un laboratoire. +1| +1|Les fleurs bleues sont situées +1|au sud-est. Grâce au laboratoire, +1|elles peuvent être transformées +1|en dynamite. + +2|Utilise la dynamite pour détruire +2|la palissade qui emprisonne les +2|quatre Blupi. Au préalable, il +2|faudra reculer les prisonniers au +2|maximum, pour les protéger de +2|l'explosion ... + +#11 +1|Objectif : +1| +1|Atteindre les maisons au nord-est. +1|Mais attention, elles sont bien +1|gardées ... + +@11 +1|Indices : +1| +1|Construis un pont vers l'île située +1|au nord-ouest, puis fabrique un +1|minimum de quatre paquets de +1|dynamite. +1| +1|Dépose ensuite la dynamite au +1|nord, assez près des bulldozers +1|pour qu'ils viennent, mais pas +1|trop tout de même .. + +2|Tant que la dynamite n'est pas +2|fabriquée, évite d'avancer au +2|nord, pour ne pas attirer les +2|bulldozers ... + +#12 +1|Objectif : +1| +1|Trois Blupi doivent rejoindre +1|le Blupi isolé sur une île éloignée +1|en direction du nord-ouest. + +@12 +1|Indices : +1| +1|Construis une cabane de jardin +1|et cultive des tomates. +1| +1|Fabrique de la dynamite avec les +1|fleurs bleues que tu trouveras +1|au nord-est. + +2|Transporte ensuite cette dynamite +2|vers l'île située assez loin à +2|l'ouest. +2|Attention: le chemin passant au +2|sud cache deux virus peu +2|offensifs ... + +#13 +1|Objectif : +1| +1|Se débarrasser des six araignées. +1| +1|Pour les quatre premières, cela +1|sera assez facile, mais pour les +1|deux dernières, il faudra ruser ... + + + + + + +2|Astuce : +2| +2|Trouve le moyen de produire du +2|poison dans le laboratoire. + +@13 +1|Indices : +1| +1|Les quatre premières araignées +1|sont attrapées avec des pièges +1|fabriqués en cueillant des fleurs +1|puis en les transformant en pièges +1|à glu dans le laboratoire. +1|Les pièges doivent être déposés +1|à côté des araignées. + +2|Les deux dernières sont empoi- +2|sonnées en transformant des +2|tomates en poison à l'aide du +2|laboratoire ... +2|Pour cela, il faudra construire +2|un pont pour permettre de trans- +2|porter les tomates jusqu'au +2|laboratoire. + +#14 +1|Objectif : +1| +1|Blupi doit simplement retourner +1|dans sa maison ... + +@14 +1|Indices : +1| +1|Sonde le sol constitué de petits +1|cailloux à la recherche de fer. +1|Dépose ensuite des planches à +1|l'endroit indiqué par le drapeau, +1|puis construis une mine de fer. +1| +1|Taille un rocher pour bâtir une +1|usine, qui te permettra +1|d'exploiter le fer ... + +2|Prends une bombe, puis saute +2|dans la jeep et dirige-toi vers +2|l'est. La jeep te protège des +2|bulldozers. +2| +2|Lorsque tu arrives à la palissade, +2|il faut rapidement descendre de +2|la jeep, déposer et faire exploser +2|la bombe, remonter dans la jeep +2|et s'éloigner ... + +#15 +1|Objectif : +1| +1|Un seul Blupi doit atteindre +1|la maison située au nord-est. + +2|Pour cela, il faudra détruire +2|les nombreuses installations +2|ennemies. + +@15 +1|Indices : +1| +1|Construis une cabane de jardin +1|et deux tours de protection +1|sur les dalles grises. +1| +1|Construis un pont pour atteindre +1|l'île à l'est. Cueille différentes +1|sortes de fleurs que tu ramènes +1|dans le camp de base. + +2|Construis un laboratoire, puis +2|fabrique de la dynamite et des +2|pièges à glu. Protège l'intérieur +2|du camp par les pièges, et +2|l'extérieur par la dynamite. +2| +2|Lorsque tu penses avoir produit +2|assez de pièges et de dynamite, +2|envoie un petit commando au +2|nord-est pour détruire le camp +2|ennemi ... + +#16 +1|Situation : +1| +1|Blupi est perdu dans une région +1|aride et sans arbres. + + + + + +2|Objectif : +2| +2|Les deux Blupi doivent rentrer +2|au village dans leurs maisons ... + +@16 +1|Indices : +1| +1|Trouve la mine de fer au nord-est, +1|puis creuse un rocher pour +1|construire une usine. +1| +1|Fabrique une bombe à retardement +1|et deux jeeps. Pars à la recherche +1|du camp ennemi au sud-ouest. + +2|Fais ensuite sauter la barrière +2|entourant le camp ennemi, en +2|essayant de faire sauter le +2|bulldozer en même temps. +2| +2|Descends vers le sud à la recherche +2|du seul arbre, et construis un +2|téléporteur ... + +#17 +1|Objectif : +1| +1|Les cinq Blupi doivent atteindre +1|chacun une maison. + +2|Attention, une maison est située +2|derrière le camp ennemi ! + + + + + + + + + +Astuce : +Il est possible de sélectionner +plusieurs Blupi simultanément +en maintenant la touche Maj +enfoncée tout en cliquant sur +les Blupi. + +@17 +1|Indices : +1| +1|Un Blupi peut tout de suite +1|aller dans la maison sur l'île +1|à l'ouest. Les quatre autres +1|doivent fuir rapidement les +1|bulldozers en partant vers le +1|nord-ouest. + +2|Assez loin en direction du +2|nord-ouest, tu rejoindras le +2|village entouré de palissades. +2| +2|Au nord du village se trouve +2|une zone riche en fer ... +2| +2|Construis un bateau, et pars +2|au nord-est avec une bombe à +2|retardement ... + +#18 +1|Situation : +1| +1|Alors que Blupi cueillait +1|tranquillement des fleurs, +1|il s'est petit à petit éloigné +1|de chez lui. Il est maintenant +1|perdu dans une région infestée +1|d'ennemis. + + + + + +2|Objectif : +2| +2|Blupi doit fuir et trouver un +2|moyen pour rentrer chez lui. + +@18 +1|Indices : +1| +1|Trouve le plan d'eau situé à +1|l'ouest et construis un bateau. +1|Il faut faire très attention +1|aux nombreux virus ... +1| +1|Avec le bateau, il suffit de +1|franchir quelques mètres pour +1|dépasser le mur de séparation. +1|Débarque alors sur la rive +1|supérieure. + +2|La maison n'est plus très +2|loin .. mais il faut éviter +2|quelques bulldozers ! + +#19 +1|Situation : +1| +1|Quatre bulldozers terrorisent +1|le village de Blupi. + + + + + +2|Objectif : +2| +2|Eliminer les bulldozers ... + +@19 +1|Indices : +1| +1|Demande à un Blupi d'extraire +1|du fer puis de construire une +1|armure. Elle te protégera du +1|feu. +1| +1|Pars vers l'est et construis +1|un bateau. Embarque et cherche +1|une autre île avec un arbre. +2|Abats l'arbre puis amène le bois +2|obtenu sur une île plus grande. +2|Construis un téléporteur qui +2|t'aménera à l'intérieur du stock. +2| +2|Déplace quelques paquets de +2|dynamite puis fais sauter le mur +2|d'enceinte. Avec la dynamite +2|sauvée, tu peux aller éliminer +2|les bulldozers ! + +#20 +1|Objectif : +1| +1|Détruire toutes les +1|installations ennemies. + +@20 +1|Indices : +1| +1|Produire un maximum de dynamite, +1|pièges, etc. avant de faire +1|sauter la barrière qui entoure +1|le camp ennemi ... + +#21 +1|Situation : +1| +1|Blupi a été capturé par le +1|méchant robot. +1|Il est maintenu prisonnier +1|dans le camp ennemi. + + + +2|Objectif : +2| +2|Blupi doit s'échapper ... +2|et retrouver sa maison. + +@21 +1|Indices : +1| +1|Prends la dynamite au nord-est. +1|Il faut ensuite la poser contre une +1|barrière bleue, en face d'une +1|trouéé dans les rochers. Le bull- +1|dozer viendra faire exploser la +1|dynamite et la barrière. + +2|Fuis alors à l'est, jusqu'à +2|la rivière. Construis un +2|bateau avec les planches. +2|Le deuxième tas de planches +2|servira à faire un deuxième +2|bateau plus loin. Avant cela, +2|il faudra se débarrasser de +2|l'électrocuteur avec le piège +2|à glu, et fabriquer une bombe +2|à retardement pour faire sauter +2|la barrière bleue tout à l'est. + +#22 +1|Objectif : +1| +1|1) Construire des bateaux. +1| +1|2) Explorer toutes les îles. + +2|3) Détruire toutes les +2| installations ennemies. + +@22 +1|Indices : +1| +1|L'île au nord-est contient +1|du minerai de fer. + +2|L'île à l'est a tout ce qu'il +2|faut pour fabriquer de la +2|dynamite et des pièges à glu. + +#23 +1|Situation : +1| +1|Blupi est un grand curieux. +1|A force de vouloir observer le +1|robot, il s'est perdu ... + + + + +2|Objectif : +2| +2|Ramener du renfort puis +2|détruire tous les ennemis ! + +@23 +1|Indices : +1| +1|Le Blupi isolé doit s'éloigner +1|du robot et aller à l'ouest. +1|Il faudra creuser un rocher +1|pour atteindre le dépot de bois, +1|puis construire un téléporteur. + +2|Avec le deuxième groupe de Blupi, +2|il faut construire un bateau, +2|trouver la bombe au nord-est et +2|faire sauter la barrière au sud. +2|Ceci permettra de ramener le +2|bois sur l'île de départ et de +2|construire un téléporteur, pour +2|rejoindre et aider le Blupi perdu ... + +#24 +1|Situation : +1| +1|La région est infestée d'ennemis. +1| + + +2|Objectif : +2| +2|Eliminer tous les ennemis ... + +@24 +1|Indices : +1| +1|Fuis vers le sud-est pour éviter +1|le feu, puis construis un bateau +1|avec le seul arbre présent. +1| +1|A l'intérieur du camp retranché, +1|tu trouveras du fer. + +2|Au nord du camp, à côté d'un +2|tout petit lac, tu trouveras +2|des oeufs ... + + +#25 +1|Depuis quelque temps, Blupi +1|soupçonne l'existence d'une +1|matière étrange amenée sur +1|sa planète par le robot : +1| +1| le Platinium ... +1| +1|Cette matière donnerait +1|accès à la technologie +1|ennemie. +2|Elle est entreposée à côté +2|de la fusée du robot. +2| + + + +2|Objectif : +2| +2|Ramène un cube de Platinium +2|sur les dalles hachurées. + +@25 +1|Indices : +1| +1|Elimine les deux bulldozers +1|avec des pièges à glu. +1| +1|Fabrique un bateau au nord +1|du premier camp ennemi, puis +1|embarque avec une bombe à +1|retardement en direction de +1|l'est. + +2|Cherche un chemin entre les +2|rochers en descendant vers +2|le sud. Le camp ennemi avec +2|la fusée se trouve tout à +2|l'est. Il faudra faire sauter +2|une barrière pour prendre le +2|Platinium. +2| +2|Ramène ensuite le Platinium +2|dans le camp de départ. + +#26 +1|Le cube de Platinium donne +1|accès à la technologie +1|ennemie. Utilise-le +1|correctement ! + + + + + +2|Objectif : +2| +2|Aide Blupi à retrouver sa +2|maison ... + +@26 +1|Indices : +1| +1|Fabrique un robot-aide avec +1|le cube de Platinium dans +1|l'usine. Fabrique également +1|une bombe à retardement. +1| +1|Prends la bombe avec le robot, +1|qui pourra traverser le camp +1|ennemi à l'ouest sans être +2|inquiété. Fais sauter la +2|barrière tout au nord, puis +2|prends des tomates qui permet- +2|tront de nourrir le Blupi resté +2|dans le camp de base. +2| +2|Dépose les tomates juste +2|avant le premier saut. + +#27 +1|Situation : +1| +1|Ne manquant pas de culot, +1|le robot a placé sa base +1|juste à côté du village +1|de Blupi. + + + +2|Objectif : +2| +2|Atteindre le camp ennemi +2|puis tout détruire ... + +@27 +1|Indices : +1| +1|Construis le plus rapidement +1|possible un téléporteur, afin +1|d'atteindre l'île aux oeufs ... +1| +1|Construis deux tours de pro- +1|tection, là où sont posés les +1|tas de pierres. +1| +1|Construis ensuite des palissades +1|à gauche et à droite des tours. + +2|Tu peux maintenant respirer ! +2| +2|Deux stratégies permettent +2|d'atteindre le camp ennemi +2|au nord : +2| +2|1) des bateaux +2|2) un pont +2| +2|A toi de choisir ... + +#28 +1|Situation : +1| +1|Blupi est un grand distrait. +1|En effet, il a construit un +1|mur autour de sa maison, +1|par erreur ... + + + + +2|Objectif : +2| +2|Blupi doit simplement (?) +2|rentrer à la maison ... + +@28 +1|Indices : +1| +1|Une petite île au nord contient +1|des oeufs. +1| +1|Il faudra traverser le camp +1|ennemi rapidement, en évitant +1|les bulldozers, du nord au +1|sud, afin de cueillir les +1|fleurs bleues. +2|Un autre Blupi en bateau +2|pourra venir les chercher pour +2|fabriquer de la dynamite ... +2| +2|Les seuls rochers exploitables +2|sont au sud du camp ennemi, à +2|l'extérieur du mur d'enceinte. +#29 +1|Situation : +1| +1|L'espace libre est de plus en +1|plus occupé par le robot et ses +1|sbires. + + + + +2|Objectif : +2| +2|Blupi doit construire son village +2|en prévoyant de bonnes défenses. +2|Il faudra ensuite passer à +2|l'offensive et éliminer tous +2|les ennemis ... + +@29 +1|Indices : +1| +1|Construire des tours au nord-est +1|et au nord-ouest, ainsi qu'au +1|sud-est. Les rochers sont +1|au nord-ouest. +1| +1|Ne pas abattre les arbres +1|autour des palissades. Ils +1|améliorent la défense contre +1|les bombes sauteuses ! + +2|Les fleurs vertes à l'est +2|permettent de fabriquer des +2|pièges à glu pour améliorer +2|la défense du village ! +2| +2|Extraire du fer au sud-ouest +2|et produire des bombes et des +2|armures ... + +#30 +1|Situation : +1| +1|Cette guerre ne peut plus durer. +1|Un accord a été conclu avec le +1|dernier robot rescapé. Blupi +1|l'aide à rejoindre sa fusée. +1|En contrepartie, celui-ci +1|s'engage à quitter définitivement +1|la planète Blupi ... + + + + +2|Objectif : +2| +2|Préparer le chemin pour que le +2|robot puisse atteindre sa fusée. +2|Vexé par sa défaite, le robot ne +2|bougera pas tant que le chemin +2|ne sera pas terminé ! + +@30 +1|Indices : +1| +1|Creuser un rocher au sud-est. +1|Abattre l'arbre et construire un +1|bateau. Partir avec le bateau à +1|la recherche d'une île au nord-est. +1|Chercher du fer puis construire +1|une mine et une usine. +2|Fabriquer une bombe qui permet- +2|tra de faire sauter les barrières +2|qui entourent le robot. +2| +2|Il ne restera plus qu'à construire +2|un pont pour que le robot puisse +2|rejoindre sa fusée ... diff --git a/resources/data/he/stories.blp b/resources/data/he/stories.blp new file mode 100644 index 0000000..49fdaa0 --- /dev/null +++ b/resources/data/he/stories.blp @@ -0,0 +1,1113 @@ +$1 +1|מטרה: +1| +1|כל בלופי חייב להכנס לבית. כדי +1|לעשות זאת, תמיד השתמשו בלחצן +1|השמאלי של העכבר + +2|)1 לחצו על בלופי +2| טבעת כחולה תופיעה מסביבו +2| ותעיד כי הוא הדמות הנבחרת. +2| +2|)2 לחצו על הבית שלו +2| +2|)3 לחצו על כפתור "המשך" +2| +2|)4 חזרו על הפעולה עבור +2| הבלופי השני. + + + + + + + + + + לאחר שקראתם את ההוראות הללו + לחצו על הקוביות שבתחתית. + +$2 +הנה עוד תרגיל, מעט יותר +מסובך: + +1|העבירו את שתי ערימות הקרשים +1|למרצפות המפוספסות שנמצאות +1|בצד ימין +1| +1|בלופי חייב לאכול עגבניות כדי +1|לאגור מספיק כח לביצוע +1|הפעולה הזאת. זיכרו שכאשר +2|הוא אוכל, הטבעת האדומה שעל +2|רגלו הופכת לכחולה. הדבר +2|מעיד על רמת האנרגיה שלו. +2| +2| אדום = עייף +2| כחול = בכושר מלא + + + +רמז: +לגלילת המסך, אתם יכולים +למשוך את העכבר לצידי המסך או +להשתמש בחיצי המקלדת. + + +$3 +1|מצאו את הביצים... +1| +1|על ידי הנחתם על המדגרה, +1|ארבעה בלופים חדשים +1|יבקעו. + + + + + + +רמז: +יהיה יותר יעיל להשתמש +בעכבר ביד אחד, ובחיצי +המקלדת ביד השניה. + + +$4 +1|מטרה: +1| +1|ארבעת הבלופים חייבים להגיע +1|לבתים באיים הצפוניים. + +2|כל בלופי חייב לאכול על מנת +2|שיהיה לו כח לקפוץ. + +$5 +1|מטרה: +1| +1|עליכם להפיל שתי קבוצות של עגבניות +1|על המרצפות המחוספסות. + +2|כדי להצליח, עליכם לכרות את העצים +2|לבנות צריף, לגדל עגבניות, +2|לשים שתי קבוצות של עגבניות +2|על המרצפות המחוספסות. +2|(לא לאכול אותם). + +$6 +1|מטרה: +1| +1|כל בלופי חייב להגיע לבית שנמצא על +1|אי קטן. +1|לצערינו, אין מספיק +1|אוכל עבור בלופי אחד. +2|אתם תצטרכו למצוא דרך +2|לייצר מספיק אוכל עבור +2|כולם. +2| +2|למזלנו, יש באי +2|הרבה עצים. + +#h1 +בלופי חי לו בשלווה באי שלו +כאשר מטאור מוזר נפל לו +באיזור צחיח. +רק מאוחר יותר, בלופי הבין +שהיבול שלו תמיד מושמד על ידי +עכביש ענקי. + +למרות שהמצב הגופני של בלופי +מצויין, עכשיו הוא מתעטש +והוא נדבק במחלה נדירה. + +#h2 +מה קורה? + +למעשה, המטאור המוזר הוא +ספינת החלל הנושאת בתוכה +רובוט מיוחד. +הרובוט הזה בונה בתי חרושת +שמייצרים אוייבים. + +בלופי חייב לנצל את כל המשאבים +הטבעיים כדי להיפטר +מהמפריעים. + +#1 +ספינת החלל שהתרסקה, הציתה +שריפה בכל היער. הכפר של +בלופי נמצא עכשיו בסכנה. + +1|מטרה: +1| +1|למנוע מהשריפה להגיע לכפר. +1|יש רק דרך אחת להצליח בפעולה: +1|לכרת כמה עצים משמאל. + + + + + + +2|רמז: +2| +2|אם בלופי חבוי בין העצים +2|לחץ על מקש הרווח, וכך יהפכו +2|העצים לשקופים באופן +2|זמני. + +@1 +1|פתרון: +1| +1|הורה לבלופי השמאלי לכרת +1|מספר עצים. שני הבלופים +1|הנותרים יעבירו את +1|הקרשים הרחק מהשריפה. + +#2 +1|המצב: +1| +1|בלופי נאבד, ונמצא רחוק מהכפר שלו +1|הוא חייב לארגן את עצמו לפני +1|שיתחיל לחפש את הכפר שלו. +1| +1|)1 לבנות צריף ולגדל +1| עגבניות + +2|)2 לבנות מדגרה כדי להשיג +2| הספקה. +2| +2|)3 להאכיל את ארבעת הבלופים +2| ולמצוא את הכפר. +2| + + +2|זהירות: +2| +2|משהו יוצא דופן עומד +2|להתרחש. + + +@2 +1|רמזים: +1| +1|בתחילה, עליכם לבנות +1|בצפון שתי גדרות +1|שימנעו מהעכביש להגיע. +1|רק אז תהיה אפשרות לבנות +2|בשלווה צריף, ולגדל +2|עגבניות. +2| +2|כדי להגיע לארבעת הבתים +2|אתם חייבים ללכת מזרחה. + + +#3 +1|מטרה: +1| +1|למנוע את הישרפותם של ארבעת +1|הבלופים. +1| +1|לסיים את החומה. + + + + +2|זהירות: +2| +2|הקרקע עשויה טחב, +2|חומר שנישרף בקלות. + +@3 +1|פתרון: +1| +1|)1 חיצבו בסלע. +1| סלעים קטנים, קל +1| יותר לחצוב. + +2|)2 בנו חומה בין שתי החומות +2| שכבר קיימות. +2| +2|)3 חכו שהשריפה תיפסק. + +#4 +1|מטרה: +1| +1|לעזור לארבעת הבלופים +1|להגיע למרצפות המפוספסות. + +@4 +1|פתרון: +1| +1|)1 כרתו עץ אחד. +1| +1|)2 העבר את הקרשים +1| לשפת המים. +1| +1|)3 בנה גשר לעבר שני +1| הבלופים העייפים. + +2|)4 חזרו על פעולה זו +2| שלוש פעמים. +2| +2|הבלופים העייפים יוכלו כעת +2|לחצות את הגשר ולהגיע +2|למרצפות המפוספסות. + +#5 +1|המלכודת: +1|זהירות, הקרקע שבה כלואים +1|הבלופים, יכולה בקלות להישרף, +1|והאש מתקרבת. +1| +1|מטרה: +1|התנגדו לאש עד +1|שתחלש. + +2|זהירות: +2|בניית חומה היא עבודה מאוד +2|מתישה עבור בלופי. ברגע +2|שיסיים, הוא ימות! + + + +רמז: +אם המשחק איטי מדי בשבילכם, +לחצו על מקש 6f כדי להגביר +את המהירות. מקש 5f מחזיר +את המשחק למהירות הנורמלית. + +@5 +1|רמזים: +1| +1|אתם חייבים לבנות ארבע חומות +1|על המרצפות האפורות. תצטרכו +1|לכרת שני עצים כדי לבנות +1|צריף ומדגרה. +1| + +2|כאשר החומות תהינה גמורות. +2|תצטרכו לחכות עד שהאש תגיע +2|ותיפסק. + +#6 +1|מטרה: +1| +1|קיימת סכנה: צריך להגן על המחנה +1|במהירות האפשרית בעזרת +1|ארבעה מגדלים. + +2|הגיעו אל המרצפות +2|המפוספסות שנמצאות +2|בדרום מזרח. + + + + + + + + + +רמז: + +ישנה אפשרות לבחור מספר בלופים +בו זמנית על ידי לחיצה רצופה על +המקש tfihs ועל כל אחד +מהבלופים. + + +@6 +1|פתרון: +1| +1|עליכם לתת לארבעת הבלופים +1|לחצוב בסלע במהירות. סלעים +1|קטנים קל יותר לחצוב +1| +1| +1|העבירו את ארבעת ערימות הסלעים +1|למרצפות האפורות, והתחילו +1|לבנות הגנה על המגדלים. +1| + +2|חכו להגעת הוירוס +2|ולמותו על ידי הזרם. +2| +2|ארבעת הבלופים האחרים +2|יכולים ללכת בשקט +2|למרצפות המפוספסות +2|שנמצאות בדרום מזרח. + +#7 +1|מטרה: +1| +1|ארבעת הבלופים צריכים להגיע +1|למרצפות המפוספסות. +1|יהיה עליכם לשמור על +1|על הבלופי הרחוק ביותר. + + + + +2|הזהרו: +2| +2|האדמה לא מתאימה כדי +2|לבנות עליה צריף. + +@7 +1|פתרון: +1| +1|בקש מבלופי להזיז את +1|העגבניות כדי שהעכבישים +1|לא יאכלו אותם. +1| +1|בעזרת בלופי אחר, קפוץ לאי +1|המזרחי, ובנה גשר שיחבר +1|את האי עם המרצפות המפוספסות. +1| + +2|קחו את העגבניות לעבר +2|הבלופי העייף, כדי +2|שיאכל אותם. + +#8 +1|מטרה: +1| +1|מנעו מבלופי אחד או שניים +1|להידבק במחלה, ומצאו תרופה עבור +1|אלו שכבר נידבקו. +1| +1|בסוף, כל בלופי חייב להכנס לתוך +1|ביתו. + + + + + + + +2|רמז: +2| +2|הרכיבו מעבדה. + +@8 +1|רמזים: +1| +1|על המעבדה להיות עשויה מסלעים. +1|הדבר יאפשר לכם להפוך את הפרחים +1|הצהובים לתרופה עבור +1|הבלופים החולים. +1| + +2|עליכם לבנות גשר כדי +2|להביא את התרופה לבלופים +2|החולים. +2| +2|הבתים נמצאים בדרום מזרח. + +#9 +1|מטרה: +1| +1|מצאו את הדרך לחצות את +1|רחבת הקרח. +1|ולהגיע אל המרצפות המפוספסות. + + + + + + +2|הערה: +2| +2|בלופי יכול ללכת על הקרח, אבל +2|הקרח מאוד חלק, ובלופי יאבד +2|הרבה מכוחו. +@9 +1|רמזים: +1| +1|צריך לבנות שני מגדלים כדי +1|להגן על הבלופים מפני העכבישים. +1| +1| +1|תצטרכו לבנות צריף ומדגרה כדי +1|שהביצים יוכלו לבקוע. +1| + +2|בלופי מאבד הרבה כח כאשר +2|הוא חוצה את רחבת הקרח. לכן, +2|צריך לתת לו עגבניות לפני +2|שהוא חוצה את הרחבה. + +#10 +1|מטרה: +1| +1|להגיע אל האי שנמצא בצפון +1|מזרח, ושם לפוצץ את הגדר. +1| + +2|כל מה שצריך לעשות עכשיו זה +2|להגיע עם ארבעת הבלופים +2|על המרצפות המפוספסות. + +@10 +1|רמזים: +1| +1|צריך לבנות גשר בכיוון ארבעת +1|האסירים הבלופים. הדבר יעזור לכם +1|לחצוב בסלע, שאותו תיקח מאוחר +1|יותר כדי לבנות מעבדה. +1| +1| +1|הפרחים הכחולים נמצאים +1|בדרום מזרח. בזכות המעבדה +1|הם יהפכו לחומר נפץ. +1| + +2|היעזרו בחומר הנפץ כדי להרוס +2|את הגדר שלוכדת בתוכה את +2|ארבעת האסירים הבלופים. +2| +2|בתחילה יש צורך להוציא את +2|האסירים ובכך, להגן עליהם +2|מפני התפוצצות. + +#11 +1|מטרה: +1| +1|להגיע אל הבתים שבצפון +1|מזרח. הזהרו! הבתים הללו +1|מוגנים כהלכה. + +@11 +1|רמזים: +1| +1|צריך לבנות גשר לעבר האי +1|שנמצא בצפון מערב. ואז +1|להכין לפחות ארבע חבילות +1|של חומר נפץ. + +2|הורידו את חומר הנפץ בצפון, +2|באיזור של הדחפורים. +2| +2| +2|כל עוד חומר הנפץ אינו מוכן, +2|הימנעו מלהגיע לאיזור הצפון, +2|אחרת תתוקפו על ידי הדחפורים. +2| + +#12 +1|מטרה: +1| +1|שלושת הבלופים צריכים להצטרף +1|לבלופי המבודד שנמצא על האי +1|בכיוון צפון מערב. + +@12 +1|רמזים: +1| +1|צריך לבנות צריף ולגדל +1|עגבניות. +1| +1|יצירת חומר נפץ נעשית מפרחים +1|כחולים שאותם ניתן למצוא +1|בצפון מזרח. + +2|העבירו את חומר הנפץ אל האי +2|שממוקם במערב. +2| +2|היזהרו! בדרך מסתתרים +2|שני וירוסים. + +#13 +1|מטרה: +1| +1|להיפטר משישה עכבישים. +1| +1|ארבעת הראשונים יהיו קלים. +1|השניים הנותרים יהיו יותר +1|קשים. + + + + + + +2|רמז: +2| +2|מיצאו איך מכינים רעל +2|במעבדה. + +@13 +1|רמזים: +1| +1|ארבעת העכבישים הראשונים יתפסו +1|על ידי מלכודות שהוכנו מפרחים +1|ירוקים במעבדה. +1| +1| +1|את המלכודות צריך למקם קרוב +1|לעכבישים. + +2|שני האחרונים יורעלו מעגבניות +2|ששונו במעבדה. +2| +2| +2| +2|צריך לבנות גשר כדי להעביר את +2|העגבניות למעבדה. + +#14 +1|מטרה: +1| +1|בלופי פשוט צריך להגיע הביתה. +1| + +@14 +1|רמז: +1| +1|חפשו ברזל באזור האבנים הקטנות +1|הורידו את הקרשים על הדגל שתמצאו +1|ובנו מכרה. +1| +1|חיצבו בסלע כדי לבנות בית מלאכה. +1|שם תוכלו להשתמש בברזל. +1| + +2|קחו את הפצצה, קיפצו אל תוך הג'יפ +2|וסעו מזרחה. הג'יפ יגן עליכם +2|מהדחפורים. +2| +2| +2|כאשר תשיגו את הגדר, תהיו חייבים +2|לעזוב את הג'יפ במהירות, להוריד +2|את פצצת הזמן, להפעיל אותה, +2|לחזור אל הג'יפ ולהתרחק מהפצצה. +2| + +#15 +1|מטרה: +1| +1|על בלופי אחד בלבד להגיע +1|אל הבית שבצפון מזרחה. + +2|כדי לפעול כך, עליכם להרוס +2|את מתקני האוייב. +2| + +@15 +1|רמזים: +1| +1|צריך לבנות צריף ושני מגדלי +1|שמירה על המרצפות האפורות. +1| +1| +1|צריך לבנות גשר כדי לחבר את האי +1|במזרח. בחרו סוג אחר של פרחים +1|והביאו אותם בחזרה למחנה. +1| + +2|צריך לבנות מעבדה, צרו חומרי נפץ +2|ומלכודות דביקות. הגנת המחנה +2|מתבצעת על ידי הנחת מלכודות +2|דביקות בתוך המחנה, והנחת חומרי +2|נפץ מחוצה לו. +2| +2|כאשר יהיו לכם מספיק חומרי נפץ +2|ומלכודות, שילחו בלופי אחד +2|לכיוון צפון מזרחה כדי להרוס +2|מחנה האוייב. + +#16 +1|המצב: +1| +1|בלופי אבד באיזור צחיח +1|ללא עצים. + + + + +2|מטרה: +2| +2|שני הבלופים חייבים לחזור +2|הביתה לכפר שלהם. + +@16 +1|רמזים: +1| +1|מיצאו את המכרה שבצפון מערב. +1|חיצבו בסלע כדי לבנות בית - +1|מלאכה, הכינו פצצת זמן, שני +1|ג'יפים וחפשו את מחנה האוייב +1|בדרום מערב. + +2|פוצצו את המחסומים שמגנים +2|על מחנה האוייב. נסו לפוצץ +2|גם את הדחפורים. +2| +2|לכו דרומה, חפשו עץ +2|ובנו ממנו משגר. + +#17 +1|מטרה: +1| +1|חמשת הבלופים חייבים +1|להגיע הביתה. + +2|זהירות! אחד מהבתים נמצא +2|מאחורי מחנה האוייב. + + + + + + + + + + + + +רמז: + +ישנה אפשרות לבחור מספר בלופים +בו זמנית על ידי לחיצה רצופה על +המקש tfihs ועל כל אחד +מהבלופים. + +@17 +1|רמזים: +1| +1|בלופי יכול עכשיו ללכת לבית שנמצא +1|בצד המערבי של האי. +1|הארבעה האחרים חייבים לעזוב +1|במהירות בגלל הדחפורים. +1|הבלופים חייבים ללכת צפון מזרחה. + +2|בהמשך, בצפון מזרח, אתם תמצאו +2|מחנה שמוקף בחומות. +2| +2|מצפון לכפר יש הרבה +2|ברזל. +2| +2|הכינו סירה, ושוטו איתה לצפון מזרח +2|עם פצצת זמן. + +#18 +1|המצב: +1| +1|בזמן שבלופי אסף פרחים +1|הוא לא תאר לעצמו שהוא +1|נמצא רחוק מהבית שלו. +1|עכשיו הוא אבוד באיזור +1|מלא באויבים. + + + + + +2|מטרה: +2| +2|בלופי חייב להימלט +2|ולמצוא את דרכו הביתה. + +@18 +1|רמזים: +1| +|1מצאו את את פלג המים במערב. +1|בנו סירה. היזהרו, +1|הרבה וירוסים מסתובבים +1|בסביבה. + +|2בעזרת הסירה, תוכלו לעבור +2|את החומה ולרדת מהסירה +2|בגדת הנהר. +2| +2|הבית כבר לא רחוק עכשיו. +2|היזהרו! אתם חייבים להימנע +2|ממפגש עם הדחפורים. + +#19 +1|המצב: +1| +1|ארבעה דחפורים מאיימים +1|על הכפר של בלופי. + + + + + +2|מטרה: +2| +2|להשמיד את הדחפורים. + +@19 +1|רמזים: +1| +1|בקשו מבלופי לחלץ ברזל, +1|ולהכין ממנו מגן. זה +1|יגן עליו מהאש. +1| +1|לכו מזרחה ובנו סירה. עלו על +1|הסירה וחפשו אי שעליו יש עץ. +1|כירתו את העץ ושימו אותו על +1|אי גדול יותר. הכינו משגר. +2|המשגר יביא אתכם לסדנת נשק. +2| +2| +2| +2|שימו קצת חומר נפץ ליד +2|החומה ופוצצו אותה. +2|בשאר חומרי הנפץ אתם +2|יכולים להשמיד את +2|הדחפורים. + +#20 +1|מטרה: +1| +1|השמדת מיתקני האוייב. +1| + +@20 +1|רמזים: +1| +1|יצרו כמה שיותר חומר נפץ +1|ומלכודות לפני שאתם מפוצצים +1|את המחסומים שמגינים על מחנה +1|האוייב. + +#21 +1|המצב: +1| +1|בלופי נלכד על ידי רובוט. +1|הוא מוחזק כאסיר בתחנה +1|של הרובוט במחנה. +1| + + + + +2|מטרה: +2| +2|בלופי חייב לברוח ולמצוא +2|את ביתו. +@21 +1|רמזים: +1| +1|קחו את חומר הנפץ מצפון מזרח. +1|מקמו אותו בסמוך למחסום הכחול, +1|מול הרווח בין הסלעים. הדחפורים +1|יגיעו, ויגרמו לחומר הנפץ להתפוצץ. +1|ההתפוצצות תשמיד את המחסום. +1| + +2|ברחו למזרח עד שתגיעו לנהר. +2|הכינו לכם סירה בעזרת הקרשים. +2|אתם תיזדקקו לערימת הקרשים +2|השניה כדי לבנות סירה מאוחר יותר. +2|אך לפני כן, עליכם לתפוס "מחשמל" +|2בעזרת המלכודות הדביקות, וליצור +2|פצצת זמן שתשמיד את המחסום +2|הכחול שנמצא במזרח. +2| + +#22 +1|מטרות: +1| +1|)1 הכנת סירות. +1| +1|)2 חקירת כל האיים. +1| +1|)3 השמדת כל מתקני האוייב. + +@22 +1|רמזים: +1| +1|באי שבצפון מזרח +1|יש הרבה ברזל. + +2|באי שבמזרח יש את כל +2|הדרוש כדי להכין חומר +2|נפץ ומלכודות דביקות. + +#23 +1|המצב: +1| +1|בלופי מאוד סקרן: לאחר +1|שהתבונן ברובוט זמן רב +1|בלופי הבין שגם הוא +1|אבוד בעצמו. + + + + + +2|מטרה: +2| +2|להכניס הספקה ולהשמיד +2|את האוייב. + + +@23 +1|רמזים: +1| +1|הבלופי המבודד חייב להתרחק +1|מהרובוט וללכת לכיוון מזרח. +1|בלופי חייב לחצוב בסלע, כך +1|שיוכל להגיע אל העצים, ושם +1|להכין משגר. +1| + +2|עם קבוצה נוספת של בלופים, +2|אתם צריכים להכין סירה, +2|למצוא את הפצצה בצפון מזרח, +2|ולפוצץ את המחסום בדרום. +2|פעולות אלו יאפשרו לכם +2|להביא את העצים אל האי +2|העזוב כדי להכין משגר. +2|זה יעזור לכם להצטרף ולעזור +2|לבלופי האבוד. +2| + +#24 +1|המצב: +1| +1|האיזור מלא באוייבים. +1| + + + +2|מטרה: +2| +2|השמדת כל האוייבים. + +@24 +1|רמזים: +1| +1|לכו צפון מזרחה כדי להימנע +1|ממגע עם האש, והכינו סירה +1|עם העץ האחרון שנשאר. +1| +1|במחנה אתם תמצאו +1|ברזל. +2|מצפון למחנה, תמצאו +2|ארבעה ביצים. + +#25 +1|בלופי חושד שהרובוט +1|הביא משהו מוזר לעולם +1|שלו: +1| +1| +1| פלטינה... +1| +1|הפלטינה, מונחת לצד הטיל. +2|תוכלו בעזרתה להשיג גישה +2|לטכנולוגיה של האוייב. +2| +2| + + +2|מטרה: +2|להביא קוביה של פלטינה +2|אל המרצפות המפוספסות. + +@25 +1|רמזים: +1| +1|צריך להרוס שני דחפורים בעזרת +1|מלכודות דביקות. להכין סירה +1|מצפון למחנה הראשון של האוייב, +1|ואז לעלות לסירה עם פצצת זמן +1|ולשוט מזרחה. +1| +1|חפשו נתיב בין סלעים אשר +1|נע דרומה. מחנה האוייב +2|נמצא רחוק במזרח. +2|שם תצטרכו לפוצץ את המחסום +2|כדי להגיע אל הפלטינה. +2| +2| +2| +2|החזירו את הפלטינה בחזרה +2|למחנה. + +#26 +1|קוביית הפלטינה תשיג עבורכם +1|גישה לטנולוגיה של האוייב. +1|השתמשו בה בצורה נכונה. + + + + + +2|מטרה: +2| +2|עיזרו לבלופי למצוא את ביתו. + +@26 +1|רמזים: +1| +1|הרכיבו מקובית הפלטינה רובוט +1|שיעזור לכם והכינו פצצת +1|זמן. +1| +1|קחו את הרובוט והפצצה. +1|הרובוט יכול לחצות את המחנה +1|המערבי של האוייב בלי שיבחינו +2|בו. פוצצו את המחסום שנמצא +2|בצפון, וקחו את העגבניות +2|כדי להאכיל את הבלופים +2|שנמצאים במחנה. +2| +2|הניחו את העגבניות +2|לפני הקפיצה הראשונה. + +#27 +1|המצב: +1| +1|לרובוט יש את החוצפה למקם +1|את הכפר שלו בסמוך לכפר +1|של הבלופים. + + + + +2|מטרה: +2| +2|להגיע אל מחנה האוייב +2|ולהשמיד הכל. + +@27 +1|רמזים: +1| +1|הכינו משגר במהירות האפשרית +1|כך שתוכלו להגיע אל האי +1|עם הביצים. +1|בנו שני מגדלי שמירה במקום +1|שנמצאות ערימות אבנים. +1|בנו גדר מצד שמאל, ומצד +1|ימין של כל מגדל שמירה. +1| + +2|עכשיו אתם יכולים להרגע! +2| +2|יש לכם שתי דרכים להגיע אל +2|מחנה האוייב שבצפון. +2|על ידי סירה או על ידי +2|בניית גשר. +2| +2|זה נתון לבחירתך! + +#28 +1|המצב: +1| +1|בזמן שבלופי בנה את ביתו +1|הוא עשה טעות: +1|הוא בנה חומה מסביב. + + + + + +2|מטרה: +2| +2|בלופי צריך פשוט להגיע הביתה. + +@28 +1|רמזים: +1| +1|באי קטן שנמצא בצפון +1|יש הרבה ביצים. +1| +1|עליכם לחצות את מחנה +1|האוייב במהירות כדי +1|להימנע ממגע עם הדחפורים +1|שמגיעים מהצפון ומהדרום, +1|כך שתוכלו לקטוף +2|פרחים כחולים. +2| +2|בלופי אחר יוכל לקחת אותם +2|ולייצר מהם חומר נפץ. +2| +2|הסלעים היחידים שתוכלו להשתמש +2|בהם, נמצאים מדרום למחנה האוייב, +2|ממש מחוץ לחומת ההגנה. +2| + +#29 +1|המצב: +1| +1|השטח הפנוי נכבש אט אט +1|על ידי הרובוט +1|ועוזריו. + + + + + +2|מטרה: +2| +2|בלופי חייב לבנות את הכפר שלו +2|ולפתח טקטיקות הגנה +2|טובות. +2| +2|אז הוא יוכל לתקוף +2|ולחסל את כל אוייביו. + +@29 +1|רמזים: +1| +1|בלופי חייב לבנות מגדלי שמירה +1|בצד הצפון מערבי, בצד הצפון +1|מזרחי, ובצד הדרום מזרחי. +1|כל הסלעים נמצאים +1|בצפון מערב. +1| +1|אל תכרתו את העצים שנמצאים +1|ליד הגדר. הם יוכלו להיות מועילים +1|כנגד הפצצה הקפיצית. + +2|הפרחים הירוקים שבמערב +2|מאפשרים לכם לייצר מלכודות +2|דביקות כדי להגן על הכפר. +2| +2|חלצו ברזל מדרום מערב, והכינו +2|ממנו פצצות ומגינים. + +#30 +1|המצב: +1| +1|המלחמה הזאת לא יכולה להמשך. +1|בלופי והרובוט האחרון הגיעו +1|להסכמה: +1|בלופי יעזור לרובוט לחזור +1|לטיל שלו, ובתמורה הרובוט +1|יעזוב את העולם של בלופי +1|לתמיד! + + + + +2|מטרה: +2| +2|להכין את נתיב הדרך לטיל +2|כדי שהרובוט יוכל לעזוב את +2|הפלנטה. הרובוט כועס על כך +2|שהפסיד בקרב ולכן הוא מסרב +2|לעבור עד שנתיב הדרך +2|יהיה מוכן. + +@30 +1|רמזים: +1| +1|חיצבו בסלע שבדרום מזרח. +1|כירתו עץ, והכינו ממנו סירה. +1|בעזרת הסירה, חפשו אי בצפון +1|מזרח, חפשו שם ברזל, והקימו +1|שם מכרה ומפעל. +1|צריך לייצר פצצה שתאפשר לכם +2|לפוצץ את המחסומים שנמצאים +2|בסביבת הרובוט. +2| +2| +2|כל מה שצריך לעשות, זה לבנות גשר +2|כדי שהרובוט יוכל לחזור +2|אל הטיל שלו. diff --git a/resources/data/info.blp b/resources/data/info.blp new file mode 100644 index 0000000..e4e1691 Binary files /dev/null and b/resources/data/info.blp differ diff --git a/resources/data/it/stories.blp b/resources/data/it/stories.blp new file mode 100644 index 0000000..1209664 --- /dev/null +++ b/resources/data/it/stories.blp @@ -0,0 +1,1116 @@ +$1 +1|Obbiettivo: +1| +1|Ogni Blupi deve entrare in una casa. +1|Per fare ciò, utilizza il pulsante +1|principale del mouse (solitamente +1|quello di sinistra). + +2|1) Clicca su un Blupi. +2| Un anello blu compare ai suoi piedi +2| per indicare che è stato selezionato. +2| +2|2) Clicca su una casa. +2| +2|3) Clicca sul pulsante "Va". +2| +2|4) Ripeti le operazioni per il secondo +2| Blupi. + + + + + + + + + + Dopo aver letto queste istruzioni, + clicca sul dado qui sotto. + +$2 +Ecco un altro esercizio un pochino più +difficile: + +1|E' sufficiente trasportare due cumuli +1|di legno sulle lastre tratteggiate +1|situate a destra ... +1| +1|Prima di fare ciò, Blupi deve mangiare +1|dei pomodori per disporre della forza +2|necessaria. Ti accorgerai che quando +2|mangia l'anello rosso ai suoi piedi +2|diventa blu. Questo anello indica il +2|suo livello d'energia: +2| +2| rosso = stanco +2| blu = in piena forma + + + +Trucco: +Per far scorrere la parte visibile puoi +portare il mouse sul bordo dello schermo, +oppure utilizzare i tasti freccia della +tastiera. + +$3 +1|Trova le uova ... +1| +1|Deponendole in un'incubatrice, +1|potrai far nascere +1|quattro Blupi nuovi di zecca ! + + + + + +Trucco: +Potrai ottenere migliori risultati +tenendo il mouse con la mano destra, +e azionando i tasti freccia +della tastiera con la mano sinistra ! + +$4 +1|Obbiettivo: +1| +1|I quattro Blupi devono raggiungere +1|le case che si trovano su altre isole +1|a nord-est. + +2|Ogni Blupi deve mangiare per avere +2|la forza di saltare ! + +$5 +1|Obbiettivo: +1| +1|Deporre due lotti di pomodori sulle +1|lastre tratteggiate. Per fare ciò è +1|necessario: +1| +1|1) Abbattere il boschetto. + +2|2) Costruire un capanno. +2| +2|3) Coltivare pomodori. +2| +2|4) Deporre due lotti di pomodori sulle +2| lastre tratteggiate (senza mangiarli). + +$6 +1|Obbiettivo: +1| +1|Ogni Blupi deve raggiungere una +1|casa su una piccola isola. +1| +1|Sfortunatamente il cibo +1|disponibile è sufficiente per un +1|solo Blupi ! +2|Sarà dunque necessario trovare il +2|mezzo per produrre cibo per tutti. +2| +2|Fortunatamente l'isola possiede +2|molti alberi ... + +#h1 +Blupi viveva tranquillamente sul +suo pianeta, sino all'arrivo di uno +strano meteorite che cade in +una regione deserta. + +Solo molto tempo dopo Blupi +si accorge che le sue coltivazioni +sono devastate da grossi ragni. + +Inoltre, mentre Blupi godeva +sempre di una salute di ferro, gli +capita di starnutire e di prendere +una strana malattia. + +#h2 +Cosa sta accadendo ? + +Ebbene, lo strano meteorite +è in realtà un razzo che trasporta +un robot molto particolare. + +Infatti, questo costruisce delle +fabbriche che producono nemici +di diversa natura. + +Blupi deve a questo punto +sfruttare tutte le risorse del +suo pianeta per riuscire a +scacciare gli intrusi ... + +#1 +La caduta del razzo ha incendiato +la foresta, in lontananza. +Il villaggio di Blupi è in pericolo ! + + +1|Obbiettivo: +1| +1|Impedire che le case del villaggio +1|brucino. Per fare ciò vi è un solo +1|mezzo: abbattere gli alberi a +1|sinistra ... + + + + + + +2|Trucco: +2| +2|Se un Blupi è nascosto tra gli +2|alberi, premi la barra spaziatrice +2|per rendere temporaneamente gli +2|alberi trasparenti. + +@1 +1|Soluzione: +1| +1|Ordinare al Blupi di sinistra di +1|abbattere degli alberi poco più +1|a ovest. + +2|I due altri Blupi trasporteranno +2|man mano le assi verso sud. +2|In questo modo saranno al riparo +2|dal fuoco ! + +#2 +1|Situazione: +1| +1|Blupi si è perso in una radura +1|distante dal suo villaggio. Deve +1|organizzarsi sul posto prima di +1|ritrovare il suo villaggio. +1| +1|1) Costruire un capanno da +1| giardino e coltivare pomodori. + +2|2) Costruire un'incubatrice per +2| ottenere rinforzi. +2| +2|3) Nutrire i quattro Blupi e partire +2| alla ricerca del villaggio ... +2| + + +2|Attenzione: +2| +2|Qualche cosa di strano sta per +2|accadere ! + +@2 +1|Indizi: +1| +1|E' prima di tutto necessario +1|costruire due palizzate a nord, +1|per bloccare il ragno. +2|Dopo sarà possibile costruire un +2|capanno da giardino e coltivare +2|pomodori in pace. +2| +2|Per raggiungere le quattro case, +2|bisogna cercare in direzione est. + +#3 +1|Obbiettivo: +1| +1|Impedire che i quattro Blupi +1|smarriti nella foresta muoiano +1|carbonizzati. +1| +1|Per fare ciò, è necessario +1|terminare la costruzione del +1|muro di protezione. + + + +2|Attenzione: +2| +2|Quando il terreno è costituito +2|da muschio, brucia +2|meravigliosamente bene ... + +@3 +1|Soluzione: +1| +1|1) Spaccare una roccia. +1| Le rocce più piccole si spaccano +1| più rapidamente ! + +2|2) Costruire un muro tra i due +2| muri esistenti. +2| +2|3) Attendere che il fuoco si +2| spenga ... + +#4 +1|Obbiettivo: +1| +1|Consentire ai quattro Blupi di +1|raggiungere le lastre tratteggiate. + +@4 +1|Soluzione: +1| +1|1) Abbattere un albero. +1| +1|2) Trasportare le assi sulla riva +1| dell'acqua. +1| +1|3) Costruire un ponte in direzione +1| dei due Blupi stanchi. + +2|4) Ripetere il tutto tre volte ... +2| +2|I Blupi stanchi possono ora +2|attraversare il ponte e raggiungere +2|le lastre tratteggiate. + +#5 +1|La trappola: +1|Attenzione, il terreno dove sono +1|prigionieri i Blupi è molto +1|infiammabile e l'incendio avanza ... +1| +1|Obbiettivo: +1|Resistere sino a che l'incendio non +1|è stato domato. + +2|Attenzione: +2|La costruzione di un muro è un +2|lavoro massacrante. E' inevitabile +2|che Blupi muoia una volta +2|concluso un muro ! + +Trucco: +Se il gioco si svolge troppo +lentamente per i tuoi gusti, premi +il tasto F6 per accelerarlo. +Premendo il tasto F5 potrai +ristabilire la velocità normale. + +@5 +1|Indizi: +1| +1|E' necessario costruire quattro +1|muri sulle lastre grigie. Per +1|fare ciò, bisognerà abbattere i +1|due boschetti disponibili per +1|costruire un capanno e +1|un'incubatrice. + +2|Quando i muri saranno terminati, +2|bisognerà pazientare sino +2|all'arrivo del fuoco e alla +2|sua estinzione ... + +#6 +1|Obbiettivo: +1| +1|Proteggi il più rapidamente +1|possibile il campo trincerato +1|tra 4 torri, perché il pericolo +1|avanza ... + +2|Potrai in seguito raggiungere le +2|lastre tratteggiate a sud-est. + + + + + + +Trucco: +E' possibile selezionare diversi +Blupi contemporaneamente +mantenendo premuto il tasto +Maiuscolo e cliccando al tempo +stesso su ogni Blupi. + +@6 +1|Soluzione: +1| +1|Bisogna chiedere in fretta ai +1|quattro Blupi di spaccare ognuno +1|una roccia. Le rocce piccole sono +1|più veloci da spaccare ! +1| +1|Trasportare i quattro cumuli di +1|pietre così ottenuti sulle lastre +1|grigie e costruire poi delle +1|torri di protezione. + +2|Attendere l'arrivo e la distruzione +2|dei virus. +2| +2|A questo punto i rimanenti quattro +2|Blupi possono tranquillamente +2|dirigersi verso le lastre +2|tratteggiate a sud-est. + +#7 +1|Obbiettivo: +1| +1|I quattro Blupi devono raggiungere +1|le lastre tratteggiate. +1|Sarà necessario prendersi cura del +1|povero Blupi più lontano ... + +2|Attenzione: +2| +2|Il terreno non consente di costruire +2|un capanno da giardino ! + +@7 +1|Soluzione: +1| +1|Chiedere ad un Blupi di prendere +1|dei pomodori per salvarli dai +1|ragni golosoni. +1| +1|Con un altro Blupi saltare sull'isola +1|ad est e costruire poi un ponte in +1|direzione delle lastre tratteggiate. + +2|Trasportare i pomodori verso il +2|Blupi affaticato, affinché si +2|possa nutrire prima di spostarsi. + +#8 +1|Obbiettivo: +1| +1|Cerca di evitare che uno o due +1|Blupi vengano contaminati, poi +1|trova l'antidoto per i Blupi +1|ammalati ... +1| +1|Alla fine, ogni Blupi dovrà entrare +1|in una casa. + + + +2|Indizio: +2| +2|Costruisci un laboratorio ... + +@8 +1|Indizi: +1| +1|E' necessario costruire un +1|laboratorio usando delle pietre. +1|Questo consentirà in seguito di +1|trasformare i fiori gialli in una +1|pozione per i Blupi ammalati. + +2|Sarà necessario costruire un +2|ponte per portare le bottiglie +2|di pozione ai Blupi ammalati. +2| +2|Le case si trovano a sud-est ... + +#9 +1|Obbiettivo: +1| +1|Trova il modo per passare oltre +1|la pista di pattinaggio ... +1| + + + +2|Nota: +2| +2|Blupi può camminare sul ghiaccio. +2|L'unico inconveniente è che Blupi +2|scivola con facilità, e così +2|facendo perde molte forze ! + +@9 +1|Indizi: +1| +1|E' necessario costruire due torri +1|per proteggersi dai ragni. +1| +1|In seguito bisogna costruire un +1|capanno da giardino e +1|un'incubatrice per far +1|schiudere le uova. + +2|Blupi perde moltissime forze +2|quando attraversa la pista da +2|pattinaggio. E' dunque necessario +2|portare dei pomodori poco prima +2|della pista di pattinaggio +2|affinché Blupi possa mangiare +2|prima di attraversarla ! + +#10 +1|Obbiettivo: +1| +1|Raggiungere l'isola a nord-est, +1|poi saltare la palizzata. + +2|Non rimane altro da fare che +2|posizionare 4 Blupi sulle lastre +2|tratteggiate ... + +@10 +1|Indizi: +1| +1|E' necessario costruire un ponte in +1|direzione dei quattro prigionieri. +1|Ciò consente di tagliare una +1|roccia da riportare verso il +1|capanno da giardino per costruire +1|un laboratorio. +1| +1|I fiori blu si trovano +1|a sud-est. Grazie al laboratorio +1|questi possono essere trasformati +1|in dinamite. + +2|Utilizza la dinamite per distruggere +2|la palizzata che tiene prigionieri i +2|quattro Blupi. Prima però +2|bisognerà far indietreggiare i +2|prigionieri il più possibile per +2|proteggerli dall'esplosione ... + +#11 +1|Obbiettivo: +1| +1|Raggiungere le case a nord-est. +1|Ma attenzione, sono ben +1|custodite ... + +@11 +1|Indizi: +1| +1|Costruisci un ponte verso l'isola +1|situata a nord-ovest, poi produci +1|un minimo di quattro candelotti +1|di dinamite. +1| +1|Posiziona in seguito la dinamite a +1|nord, abbastanza vicino ai bulldozer +1|affinchè questi si avvicinino, ma +1|senza esagerare.. + +2|Fintanto che la dinamite non è +2|pronta evita di avanzare verso +2|nord per non attirare i +2|bulldozer ... + +#12 +1|Obbiettivo: +1| +1|Tre Blupi devono raggiungere +1|il Blupi isolato su un'isola lontana +1|in direzione nord-ovest. + +@12 +1|Indizi: +1| +1|Costruisci un capanno da giardino +1|e coltiva pomodori. +1| +1|Produci della dinamite con i +1|fiori blu che troverai +1|a nord-est. + +2|Trasporta in seguito questa +2|dinamite verso l'isola che si +2|trova abbastanza lontano a +2|ovest. +2|Attenzione: il sentiero che passa a +2|sud nasconde due virus non molto +2|pericolosi ... + +#13 +1|Obbiettivo: +1| +1|Sbarazzarsi dei sei ragni. +1| +1|Per i primi quattro, la cosa +1|è abbastanza semplice, ma per gli +1|ultimi due, dovrai ricorrere a dei +1|trucchi ... + +2|Trucco: +2| +2|Trova il modo di produrre del +2|veleno nel laboratorio. + +@13 +1|Indizi: +1| +1|I primi quattro ragni vengono +1|catturati con delle trappole +1|costruite cogliendo dei fiori +1|e trasformandoli poi in trappole +1|collose in laboratorio. +1|Le trappole devono essere messe +1|vicino ai ragni. + +2|Gli ultimi due vengono avvelenati +2|trasformando i pomodori +2|in veleno con l'aiuto del +2|laboratorio ... +2|Per fare ciò sarà necessario +2|costruire un ponte per consentire +2|di trasportare i pomodori sino +2|al laboratorio. + +#14 +1|Obbiettivo: +1| +1|Blupi deve semplicemente tornare +1|nella sua casa ... + +@14 +1|Indizi: +1| +1|Sonda il terreno costituito da +1|piccoli sassi alla ricerca di ferro. +1|Posiziona in seguito delle assi +1|nel posto indicato con la bandierina +1|e costruisci una miniera di ferro. +1| +1|Taglia una roccia per costruire +1|una fabbrica che ti consentirà di +1|sfruttare il ferro ... + +2|Prendi una bomba poi salta nella +2|jeep e dirigiti verso est. La jeep +2|ti protegge dai bulldozer. +2| +2|Quando giungi vicino alla palizzata +2|devi scendere rapidamente dalla +2| jeep, posizionare e far esplodere +2|la bomba, risalire sulla jeep +2|e allontanarti ... + +#15 +1|Obbiettivo: +1| +1|Un solo Blupi deve raggiungere +1|la casa situata a nord-est. + +2|Per fare ciò sarà necessario +2|distruggere le numerose +2|postazioni nemiche. + +@15 +1|Indizi: +1| +1|Costruisci un capanno da giardino +1|e due torri di protezione sulle +1|lastre grigie. +1| +1|Costruisci un ponte per raggiungere +1|l'isola ad est. Cogli vari tipi di +1|fiori che riporterai al campo base. + +2|Costruisci un laboratorio poi +2|produci della dinamite e delle +2|trappole collose. Proteggi l'interno +2|del campo con le trappole e +2|l'esterno con la dinamite. +2| +2|Quando ritieni di aver prodotto +2|trappole e dinamite a sufficienza +2|spedisci un piccolo commando +2|verso nord-est per distruggere +2|il campo nemico ... + +#16 +1|Situazione: +1| +1|Blupi si è smarrito in una regione +1|arida e priva di alberi. + + +2|Obbiettivo: +2| +2|I due Blupi devono rientrare +2|al villaggio nelle loro case ... + +@16 +1|Indizi: +1| +1|Trova la miniera di ferro a +1|nord-est poi taglia una roccia +1|per costruire una fabbrica. +1| +1|Costruisci una bomba a scoppio +1|ritardato e due Jeep. Parti alla +1|ricerca del campo nemico a +1|sud-ovest. + +2|In seguito fai saltare la barriera +2|che circonda il campo nemico +2|cercando di far saltare al tempo +2|stesso il bulldozer. +2| +2|Scendi verso sud alla ricerca +2|dell'unico albero e costruisci un +2|teletrasporto ... + +#17 +1|Obbiettivo: +1| +1|I cinque Blupi devono raggiungere +1|ognuno una casa. + +2|Attenzione, una casa si trova +2|dietro il campo nemico ! + + +Trucco: +E' possibile selezionare +diversi Blupi contemporaneamente +mantenendo premuto il tasto +Maiuscolo e cliccando al tempo +stesso sui Blupi. + +@17 +1|Indizi: +1| +1|Un Blupi può immediatamente +1|raggiungere la casa sull'isola +1|a ovest. Gli altri quattro +1|devono fuggire rapidamente dai +1|bulldozer partendo verso +1|nord-ovest. + +2|Abbastanza lontano in direzione +2|nord-ovest raggiungerai il +2|villaggio circondato da palizzate. +2| +2|A nord del villaggio si trova +2|una zona ricca di ferro ... +2| +2|Costruisci un'imbarcazione e parti +2|verso nord-est con una bomba a +2|scoppio ritardato ... + +#18 +1|Situazione: +1| +1|Mentre Blupi coglieva +1|tranquillamente dei fiori, +1|si è poco a poco allontanato +1|da casa sua. Ora si è smarrito +1|in una regione infestata dai +1|nemici. + + + + + +2|Obbiettivo: +2| +2|Blupi deve fuggire e trovare un +2|modo per tornare a casa sua. + +@18 +1|Indizi: +1| +1|Trova la distesa d'acqua che si +1|trova a ovest e costruisci +1|un'imbarcazione. E' necessario +1|prestare molta attenzione ai +1|numerosi virus ... +1| +1|Con l'imbarcazione è sufficiente +1|fare qualche metro per +1|oltrepassare il muro di divisione. +1|Sbarca allora sulla riva +1|superiore. + +2|La casa non è più molto lontana ... +2|ma è necessario evitare qualche +2|bulldozer ! + +#19 +1|Situazione: +1| +1|Quattro bulldozer terrorizzano +1|il villaggio di Blupi. + + +2|Obbiettivo: +2| +2|Eliminare i bulldozer ... + +@19 +1|Indizi: +1| +1|Chiedi a un Blupi di estrarre +1|del ferro e di costruire poi una +1|armatura. Questa ti proteggerà +1|dal fuoco. +1| +1|Parti verso est e costruisci una +1|barca. Prendi il largo e cerca +1|un'altra isola con un albero. +2|Abatti l'albero poi riporta la legna +2|che hai ottenuto su un'isola più +2|grande. Costruisci un teletrasporto +2|che ti porterà all'interno +2|dell'armeria. +2| +2|Posiziona qualche candelotto di +2|dinamite attorno al muro e fallo +2|saltare. Con la dinamite rimasta +2|puoi andare a eliminare i +2|bulldozer ! + +#20 +1|Obbiettivo: +1| +1|Distruggere tutte le postazioni +1|nemiche. + +@20 +1|Indizi: +1| +1|Produrre più dinamite possibile, +1|più trappole possibili, ecc ... +1|prima di far saltare la barriera +1|che circonda il campo nemico ... + +#21 +1|Situazione: +1| +1|Blupi è stato catturato dal +1|robot cattivo. +1|Ora è tenuto prigioniero +1|nel campo nemico. + + + +2|Obbiettivo: +2| +2|Blupi deve fuggire ... +2|e tornare a casa sua. + +@21 +1|Indizi: +1| +1|Prendi la dinamite a nord-est. +1|Posizionala in seguito contro una +1|barriera blu di fronte a un +1|passaggio tra le rocce. Il bulldozer +1|arriverà e farà esplodere la +1|dinamite e la barriera. + +2|Fuggi allora verso est, sino al fiume. +2|Costruisci una barca con delle assi. +2|Il secondo cumulo di assi servirà +2|a costruire una seconda barca +2|più avanti. Prima di ciò, sarà +2|necessario sbarazzarsi del +2|folgoratore con la trappola +2|collosa e costruire una bomba a +2|scoppio ritardato per far saltare +2|la barriera blu a est. + +#22 +1|Obbiettivo: +1| +1|1) Costruire delle barche. +1| +1|2) Esplorare tutte le isole. + +2|3) Distruggere tutte le +2| postazioni nemiche. + +@22 +1|Indizi: +1| +1|L'isola a nord-est contiene del +1|minerale di ferro. + +2|L'isola a est dispone di tutto +2|quanto serve per produrre della +2|dinamite e delle trappole collose. + +#23 +1|Situazione: +1| +1|Blupi è un gran curiosone: dopo +1|avere osservato il robot, per lungo +1|tempo, si è accorto di essersi +1|smarrito ... + + +2|Obbiettivo: +2| +2|Far arrivare dei rinforzi poi +2|distruggere tutti i nemici ! + +@23 +1|Indizi: +1| +1|Il Blupi isolato deve allontanarsi +1|dal robot e andare verso ovest. +1|Sarà necessario spaccare una +1|roccia per raggiungere il +1|deposito di legna, poi costruire +1|un teletrasporto. + +2|Con il secondo gruppo di Blupi, +2|sarà necessario costruire una +2|barca, trovare la bomba a +2|nord-est e far saltare la +2|barriera a sud. Ciò consentirà +2|di riportare la legna sull'isola +2|di partenza e di costruire un +2|teletrasporto per raggiungere +2|e aiutare il Blupi smarrito ... + +#24 +1|Situazione: +1| +1|La regione è infestata dai nemici. +1| + + +2|Obbiettivo: +2| +2|Eliminare tutti i nemici ... + +@24 +1|Indizi: +1| +1|Fuggi verso sud-est per evitare +1|l'incendio, poi costruisci una barca +1|con il solo albero di cui disponi. +1| +1|All'interno del campo trincerato +1|troverai del ferro. + +2|A nord del campo, vicino a un +2|piccolo lago, troverai delle uova ... + + +#25 +1|Da qualche tempo Blupi sospetta +1|dell'esistenza di uno strano +1|materiale portato sul suo +1|pianeta dal robot: +1| +1| il Platinium ... +1| +1|Questo materiale, che si trova +2|vicino al razzo del robot, +2|consentirebbe l'accesso alla +2|tecnologia nemica. +2| + +2|Obbiettivo: +2| +2|Riporta un cubo di Platinium +2|sulle lastre tratteggiate. + +@25 +1|Indizi: +1| +1|Elimina i due bulldozer con le +1|trappole collose. Costruisci una +1|barca a nord del primo campo +1|nemico poi prendi il largo con +1|una bomba a scoppio ritardato +1|in direzione est. + +2|Cerca una strada tra le rocce e +2|scendi verso sud. Il campo nemico +2|con il razzo si trova a est. Sarà +2|necessario far saltare una barriera +2|per prendere il Platinium. +2| +2|Riporta in seguito il Platinium nel +2|campo di partenza. + +#26 +1|Il cubo di Platinium consente +1|l'accesso alla tecnologia nemica +1|se utilizzato correttamente. + +2|Obbiettivo: +2| +2|Aiuta Blupi a ritrovare la sua +2|casa ... + +@26 +1|Indizi: +1| +1|Costruisci un robot-aiutante con +1|il cubo di Platinium in fabbrica. +1|Costruisci inoltre una bomba a +1|scoppio ritardato. +1| +1|Prendi la bomba con il robot che +1|potrà attraversare il campo +1|nemico a ovest senza problemi. +2|Fai saltare la barriera a nord, +2|poi prendi dei pomodori che +2|consentiranno di nutrire il Blupi +2|rimasto nel campo base. +2| +2|Deponi i pomodori appena prima +2|del primo salto. + +#27 +1|Situazione: +1| +1|Con gran faccia tosta, il robot +1|ha posto la sua base proprio +1|vicino al villaggio di Blupi. + + + +2|Obbiettivo: +2| +2|Raggiungere il campo nemico +2|poi distruggere tutto ... + +@27 +1|Indizi: +1| +1|Costruisci il più rapidamente +1|che puoi un teletrasporto, al fine +1|di raggiungere l'isola con le uova ... +1|Costruisci due torri di protezione +1|dove si trovano i cumuli di pietre. +1|Costruisci in seguito delle palizzate +1|a sinistra e a destra delle torri. + +2|Ora puoi tirare un sospiro di +2|sollievo ! +2| +2|Hai due possibilità per raggiungere +2|il campo nemico a nord: +2| +2|1) delle barche +2|2) un ponte +2| +2|A te la scelta ... + +#28 +1|Situazione: +1| +1|Blupi è un gran distratto. +1|Infatti ha costruito un muro +1|intorno alla sua casa, per +1|sbaglio ... + + +2|Obbiettivo: +2| +2|Blupi deve semplicemente +2|rientrare a casa ... + +@28 +1|Indizi: +1| +1|In un'isoletta a nord si trovano +1|molte uova. +1| +1|Sarà necessario attraversare il +1|campo nemico in fretta evitando +1|i bulldozer, da nord a sud, al +1|fine di cogliere i fiori blu. +2|Un altro Blupi in barca potrà +2|venire a prenderli per produrre +2|della dinamite ... +2| +2|Le uniche rocce che possono +2|essere usate sono a sud del +2|campo nemico, fuori dal muro +2|di cinta. + +#29 +1|Situazione: +1| +1|Lo spazio libero è sempre più +1|occupato dal robot e dai suoi +1|scagnozzi. + + + + +2|Obbiettivo: +2| +2|Blupi deve costruire il suo villaggio +2|prevedendo delle difese efficaci. +2|Sarà necessario in seguito passare +2|all'attacco ed eliminare tutti i +2|nemici ... + +@29 +1|Indizi: +1| +1|Costruire delle torri a nord-est, +1|a nord-ovest e a sud-est. +1|Le rocce si trovano a nord-ovest. +1| +1|Non abbattere gli alberi +1|intorno alle palizzate. Questi +1|migliorano le difese contro +1|le bombe saltatrici ! + +2|I fiori verdi a est consentono di +2|produrre delle trappole collose +2|per migliorare la difesa del +2|villaggio ! +2| +2|Estrarre del ferro a sud-ovest +2|e costruire delle bombe e delle +2|armature ... + +#30 +1|Situazione: +1| +1|Questa guerra non può più durare. +1|Un accordo è stato concluso con +1|l'ultimo robot sopravvissuto. Blupi +1|lo aiuta a raggiungere il suo +1|razzo. E questo s'impegna a +1|lasciare definitivamente il +1|pianeta Blupi ... + + + + +2|Obbiettivo: +2| +2|Preparare il cammino affinché il +2|robot possa raggiungere il suo +2|razzo. Offeso per aver perso, il +2|robot non si muoverà fintanto +2|che il sentiero non verrà +2|terminato ! + +@30 +1|Indizi: +1| +1|Spaccare della roccia a sud-est. +1|Abbattere un albero e costruire +1|una barca. Partire con la barca +1|alla ricerca di un'isola a nord-est. +1|Cercare del ferro poi costruire +1|una miniera e una fabbrica. +2|Costruire una bomba che +2|consentirà di far saltare le +2|barriere che circondano il robot. +2| +2|Non rimarrà altro che costruire +2|un ponte affinché il robot possa +2|raggiungere il suo razzo ... diff --git a/resources/data/pl/stories.blp b/resources/data/pl/stories.blp new file mode 100644 index 0000000..d2ac7ba --- /dev/null +++ b/resources/data/pl/stories.blp @@ -0,0 +1,1110 @@ +$1 +1|Cel: +1| +1|Każdy Blupi musi trafić do domu. By +1|to osiągnąć, zawsze używaj lewego +1|przycisku myszy. + +2|1) Kliknij na Blupiego +2| Niebieski pierścień który się pojawi +2| oznacza że jest on zaznaczony. +2| +2|2) Kliknij na jego dom +2| +2|3) Kliknij na przycisk "Idź" +2| +2|4) Powtórz czynności dla +2| kolejnego Blupiego. + + + + + + + + + + Po przeczytaniu tych instrukcji + kliknij na kostkę poniżej. + +$2 +Tutaj mamy drugie ćwiczenie, +nieco bardziej zaawansowane: + +1|Przenieś oba stosy desek na +1|nawierzchnię docelową po +1|prawej stronie. +1| +1|Blupi musi jeść pomidory by +1|mieć dość sił by wykonać +1|to zadanie. Zwróć uwagę na fakt +2|że gdy je, czerwona obwódka wokół +2|jego stóp zmienia się w niebieską. +2|To określa jego poziom siły. +2| +2| czerwony = zmęczony +2| niebieski = w pełni sił + + + +Podpowiedź: +By przewinąć ekran, możesz +zbliżyć kursor myszy do krawędzi +ekrany, lub wykorzystać strzałki +na klawiaturze. + +$3 +1|Znajdź jaja ... +1| +1|Po umieszczeniu ich w +1|wylęgarce, pojawi się +1|czterech nowych Blupich. + + + + + + +Podpowiedź: +Najefektywniej jest grać +używając myszy w jednej ręce +podczas gdy druga ręka +spoczywa na strzałkach klawiatury. + +$4 +1|Cel: +1| +1|Czterech Blupich musi trafić do +1|domów na północnych wyspach. + +2|Każdy Blupi musi jeść by mieć +2|dość siły by skoczyć. + +$5 +1|Cel: +1| +1|Umieść 2 stosy pomidorów +1|na nawierzchni docelowej. + +2|By to osiągnąć musisz ściąć drzewo +2|wybudować szopkę ogrodową, zasadzić +2|pomidory i przenieść 2 stosy pomidorów +2|na nawierzchnię docelową. +2|(nie możesz ich zjeść). + +$6 +1|Cel: +1| +1|Każdy Blupi musi trafić do domu +1|na małej wyspie. +1|Niestety, jedzenia starczy +1|dla tylko jednego Blupiego. +2|Musisz wymyślić sposób na +2|wyprodukowanie wystarczającej ilości +2|jedzenia dla wszystkich. +2| +2|Na szczęście, wyspa jest +2|obfita w drewno. + +#h1 +Blupi żył sobie spokojnie na swojej +wyspuegdy nagle wielki meteoryt +spadł na suchy region. + +Po chwili Blupi odkrył że jego +plony są niszczone przez pająki. + + +Pomimo bycia w pełni sprawnym +fizycznie Blupi zaczął kaszleć +i złapał infekcję. + +#h2 +Co się dzieje ? + +Cóż, ten dziwny meteoryt to tak +naprawdę statek kosmiczny +transportujący pewnego robota. + +Ten robot buduje fabryki, które +produkują wrogów. + +Blupi musi wykorzystać wszelkie +naturalne zasoby by pozbyć się +intruzów. + +#1 +Uderzenie statku kosmicznego +wywołało pożar lasu. Wioska +Blupich jest zagrożona. + +1|Cel: +1| +1|Zapobiegnij spaleniu wioski. +1|Jest tylko jedna metoda by to +1|zrobić: Zetnij trochę drzew po +1|lewej stronie. + + + + + + +2|Podpowiedź: +2| +2|Jeśli Blupi jest ukryty za drzewami, +2|naciśnij klawisz Spacji. Spowoduje +2|to tymczasowe wyświetlanie drzew +2|jako przezroczyste. + +@1 +1|Solucja: +1| +1|Każ Blupiemu po lewej ściąć +1|trochę drzew. Pozostali Blupi +1|powinni wynosić deski z dala +1|od ognia. + +#2 +1|Sytuacja: +1| +1|Blupi jest daleko od swojej wioski +1|i się zgubił. Teraz musi się +1|zorganizowaćzanim znajdzie +1|swoją wioskę. +1| +1|1) Zbuduj szopkę ogrodową i zasadź +1| pomidory. + +2|2) Zbuduj wylęgarkę by uzyskać +2| wsparcie +2| +2|3) Nakarm czterech Blupich +2| i ruszaj znaleźć wioskę. +2| + + +2|Uważaj: +2| +2|Wydarzy się coś niespodziewanego. + + +@2 +1|Solucja: +1| +1|Na początek musisz zbudować +1|dwie palisady na północy +1|by powstrzymać pająka przed +1|przyjściem. +1|Dopiero wtedy wybuduj +2|szopkę ogrodową i sadź +2|pomidory w spokoju. +2| +2|By trafić do wioski +2|musisz iść na wschód. + + +#3 +1|Cel: +1| +1|Uchroń 4 zagubionych Blupich +1|przed spaleniem +1| +1|Ukończ mur. + + + + +2|Uwaga: +2| +2|Ziemia wyścielona jest mchem +2|który jest bardzo łatwopalny. + +@3 +1|Solucja: +1| +1|1) Wykuj skałę. +1| Mniejsze kamienie są szybsze +1| do wykucia + +2|2) Zbuduj mur pomiędzy dwoma +2| istniejącymi murami +2| +2|3) Poczekaj aż ogień wygaśnie. + +#4 +1|Cel: +1| +1|Czterech Blupich musi wejść +1|na nawierzchnię docelową. + +@4 +1|Solucja: +1| +1|1) Zetnij drzewo +1| +1|2) Przenieś deski na +1| brzeg. +1| +1|3) Zbuduj most w kierunku +1| dwóch zmęczonych Blupich. + +2|4) Powtórz operację +2| trzykrotnie. +2| +2|Zmęczeni Blupi mogą teraz +2|przejść przez most i dotrzeć +2|do nawierzchni docelowej. + +#5 +1|Pułapka: +1|Uwaga, ziemia gdzie więzione +1|są Blupi jest łatwopalna +1|a ogień jest coraz bliżej. +1| +1|Cel: +1|Wytrzymaj aż do +1|wygaszenia pożaru. + +2|Uwaga: +2|Budowa muru to bardzo +2|męcząca praca dla Blupiego, +2|on zginie po skończeniu pracy! + + + +Podpowiedź: +Jeśli gra jest dla ciebie za wolna +wciśnij klawisz F6 by przyspieszyć +rozgrywkę. Klawisz F5 przywraca +zwykłą prędkość gry. + +@5 +1|Solucja: +1| +1|Musisz zbudować 4 kawałki muru +1|na szarej nawierzchni. Musisz +1|ściąc 2 drzewa by zbudować +1|szopkę ogrodową oraz +1|wylęgarkę. + +2|Gdy mury będą gotowe +2|musisz poczekać aż ogień +2|wygaśnie. + +#6 +1|Cel: +1| +1|Zbliża się niebezpieczeństwo: +1|zabezpiecz obóz tak szybko jak +1|to możliwe za pomocą 4 wież. + +2|Następnie będziesz mógł +2|iść na nawierzchnię docelową +2|na południowym wschodzie. + + + + + + + + + +Podpowiedź: + +Możesz zaznaczyć wielu Blupich +naraz jeśli przytrzymasz klawisz +Shift podczas klikania na +każdego Blupiego. + + +@6 +1|Solucja: +1| +1|Musisz kazać czterem Blupim +1|szybko skuć skałę. +1|Mniejsze skały są łatwiejsze +1|do skucia. +1| +1|Przenieś 4 sterty skał +1|na szary teren i zacznij +1|budować wieże ochronne. + +2|Poczekaj aż wirusy zostaną +2|zneutralizowane przez wieże. +2| +2|Pozostali Blupi mogą +2|spokojnie udać się w +2|kierunku nawierzchni docelowych +2|na południowym wschodzie. + +#7 +1|Cel: +1| +1|Czterech Blupich musi dotrzeć +1|do nawierzchni docelowej. +1|Musisz uważać na +1|najdalszego Blupiego. + + + + + +2|Uważaj: +2| +2|Ziemia nie jest odpowiednia +2|do sadzenia pomidorów. + +@7 +1|Solucja: +1| +1|Każ Blupim podnieść pomidory +1|przez co pająki nie mogą +1|ich zjeść. +1| +1|Jeden z Blupich musi +1|przeskoczyć na wschodnią +1|wyspę i wybudować most +1|prowadzący do nawierzchni +1|docelowej. + +2|Przynieś pomidory do +2|zmęczonego Blupiego, żeby +2|on mógł je zjeść. + +#8 +1|Cel: +1| +1|Uchroń jednego lub dwóch Blupich +1|przed zarażeniem i znajdź +1|lekarstwo dla zarażonych. +1| +1|Następnie zaprowadź Blupich +1|do domu. + + + + + + + +2|Podpowiedź: +2| +2|Zbuduj laboratorium. + +@8 +1|Solucja: +1| +1|Laboratorium buduje się z +1|kamieni. W nim możesz przemienić +1|bukiet żółtych kwiatów +1|na lekarstwo dla chorych +1|Blupich. + +2|Musisz zbudować most by przynieść +2|lekarstwo zarażonym Blupim. +2| +2|Domy są na południowym wschodzie. + +#9 +1|Cel: +1| +1|Znajdź sposób na przekroczenie +1|lodowego pola. +1| + + + + + + +2|Notka: +2| +2|Blupi może chodzić po lodzie. +2|Jednak z uwagi na poślizg +2|straci przy tym mnóstwo sił. + +@9 +1|Solucja: +1| +1|Dwie wieże muszą zostać zbudowane +1|by chronić Blupich przed pająkami +1| +1|Musisz zbudować szopkę ogrodową +1|oraz wylęgarkę by pozwolić +1|jajkom wykluć się. + +2|Blupi traci dużo sił podczas +2|przekraczania lodu. +2|Musisz więc kazać mu podnieść +2|pomidory zanim wejdzie na lód. + +#10 +1|Cel: +1| +1|Dotrzyj na wyspę na północnym +1|zachodzie i wysadź palisadę +1|w powietrze. + +2|Następnie umieść czterech +2|Blupich na nawierzchni docelowej + +@10 +1|Solucja: +1| +1|Zbuduj most prowadzący do +1|uwięzionych Blupich. To umożliwi +1|skucie skał które posłużą do +1|budowy laboratorium. +1| +1|Niebieskie kwiaty są na +1|południowym wschodzie. +1|W laboratorium można +1|wykorzystać je do produkcji +1|dynamitu. + +2|Użyj dynamitu by zniszczyć +2|palisadę blokującą drogę +2|więźniom. +2| +2|Najpierw jednak musisz +2|kazać im odsunąć się od palisady +2|by nie stała im się krzywda. + +#11 +1|Cel: +1| +1|Idź do domów na północnym +1|wschodzie. Bądź ostrożny, +1|one są silnie chronione. + +@11 +1|Solucja: +1| +1|Zbuduj most w kierunku +1|wyspy na północnym zachodzie +1|i stwórz przynajmniej +1|4 paczki dynamitu. + +2|Połóż dynamit na północy +2|w miarę blisko buldożerów +2| +2|Dopóki nie zbierzesz dość +2|dynamitu nie idź za daleko, +2|inaczej zwabisz buldożery. + +#12 +1|Cel: +1| +1|Trzech Blupich musi dotrzeć do +1|samotnego Blupiego na wyspie +1|na północnym zachodzie. + +@12 +1|Solucja: +1| +1|Wybuduj szopkę ogrodową +1|i zasadź pomidory. +1| +1|Stwórz dynamit z niebieskich +1|kwiatów rosnących na północnym +1|wschodzie. + +2|Zanieś dynamit na wyspę +2|położoną na zachodzie. +2| +2|Uważaj, po drodze kryją się +2|2 wirusy. + +#13 +1|Cel: +1| +1|Pozbądź się 6 pająków. +1| +1|Pierwsza czwórka będzie łatwa +1|Pozostała dwójka może sprawić +1|więcej kłopotów. + + + + + + +2|Podpowiedź: +2| +2|Odkryj jak stworzyć truciznę +2|w laboratorium. + +@13 +1|Solucja: +1| +1|Pierwsze cztery pająki można +1|złapać w pułapki z zielonych +1|kwiatów przetworzonych w +1|laboratorium. +1| +1|Pułapki muszą być położone +1|niedaleko pająków. + +2|Ostatnia dwójka musi być +2|zatruta pomidorami które +2|zostały zatrute w +2|laboratorium. +2| +2|Zbuduj most by zanieść +2|pomidory do laboratorium. + +#14 +1|Cel: +1| +1|Blupi musi trafić do domu. +1| + +@14 +1|Solucja: +1| +1|Szukaj żelaza pod małymi +1|kamyczkami. Połóż deski pod +1|flagą i zbuduj kopalnię. +1| +1|Skuj skałę i zbuduj warsztat +1|w którym zrobisz użytek +1|z żelaza. + +2|Weź bombę, wsiądź do Jeepa +2|i jedź na wschód. Jeep +2|ochroni cię przed +2|buldożerami. +2| +2|Gdy dotrzesz do palisady, +2|musisz szybko wysiąść z auta, +2|upuścić bombę, uruchomić ją, +2|wrócić do samochodu i wiać +2|gdzie pieprz rośnie. + +#15 +1|Cel: +1| +1|Jeden z Blupich musi dotrzeć +1|do domu na północnym wschodzie. + +2|By to osiągnąć, musisz +2|zniszczyć wiele wrogich +2|instalacji. + +@15 +1|Solucja: +1| +1|Zbuduj szopkę ogrodową i wieże +1|ochronne na szarym terenie. +1| +1|Zbuduj most by połączyć wyspę +1|na wschodzie. Zbierz kwiaty +1|i przynieś je z powrotem do bazy. + +2|Zbuduj laboratorium, stwórz +2|dynamit i klejące pułapki. +2|Chroń obozu od środka za pomocą +2|klejących pułapek i od zewnątrz +2|za pomocą dynamitu. +2| +2|Gdy będziesz mieć wystarczająco +2|dużo dynamitu i pułapek wyślij +2|mały oddział na północny wschód +2|by zniszczyć przeciwny obóz. + +#16 +1|Sytuacja: +1| +1|Blupi zgubił się na jałowej +1|części planety, na której nie ma +1|drzew. + + + +2|Cel: +2| +2|Obaj Blupi muszą wrócić do +2|swojej wioski. + +@16 +1|Solucja: +1| +1|Znajdź kopalnię na północnym +1|wschodzie, skuj skałę by zbudować +1|warsztat, zbuduj bombę zegarową +1|i 2 Jeepy i znajdź przeciwny obóz +1|na południowym zachodzie. + +2|Wysadź barierę chroniącą wrogi +2|obóz. +2|Postaraj się wysadzić przy tym +2|również buldożery. +2| +2|Idź na południe i poszukać jedynego +2|drzewa i zbuduj z niego teleporter. + +#17 +1|Cel: +1| +1|Pięciu Blupich musi znaleźć dom + +2|Uwaga, jeden z domów znajduje się +2|za wrogim obozem. + + + + + + + + + + + + +Wskazówka: + +Możesz zaznaczyć wielu Blupich +jednocześnie przez trzymanie +wciśniętego klawisza Shift podczas +klikania na każdym Blupim. + +@17 +1|Solucja: +1| +1|Blupi może iść do domu na +1|zachodniej części wyspy. +1|Pozostała czwórka musi iść +1|dość szybko by nie paść ofiarą +1|buldożerów. Blupi muszą iść na +1|północny wschód. + +2|Nieco dalej znajdziesz wioskę +2|otoczoną palisadami. +2| +2|W północnej części wioski +2|są duże pokłady żelaza. +2| +2|Stwórz łódź i podążaj na +2|północny wschód z bombą +2|zegarową. + +#18 +1|Sytuacja: +1| +1|Gdy Blupi zbierał kwiaty, +1|niepostrzeżenie oddalił się +1|od swojego domu. Teraz jest +1|zagubiony w regionie +1|pełnym wrogów. + + + + + +2|Cel: +2| +2|Blupi musi uciec i znaleźć +2|drogę powrotną do domu. + +@18 +1|Solucja: +1| +1|Znajdź zbiornik wodny na zachodzie +1|Stwórz łódź. Uważaj na wirusy +1|kręcące się w okolicy. + + +2|W łodzi możesz ominąć mur +2|i wyokrętować na brzegu rzeki. +2| +2| +2|Dom jest już niedaleko. +2|Musisz jednak uważać na buldożery. + + +#19 +1|Sytuacja: +1| +1|Cztery buldożery zagrażają +1|wiosce Blupiego. + + + + + +2|Cel: +2| +2|Zniszcz buldożery + +@19 +1|Solucja: +1| +1|Każ Blupiemu wydobywać żelazo +1|i zbudować zbroję. Ochroni go +1|ona przed ogniem. +1| +1|Idź na wschód i zbuduj łódź. +1|Wejdź na pokład i poszukaj innej +1|wyspy z drzewami. Zetnij drzewo +1|i przetransportuj deski na większą +2|wyspę. Stwórz teleporter. +2|Przeniesie cię on do zbrojowni. +2| +2| +2|Umieść trochę dynamitu niedaleko +2|muru otaczającego teren i wysadź +2|go. +2|Za pomocą reszty dynamitu możesz +2|zniszczyć buldożery. + +#20 +1|Cel: +1| +1|Zniszcz wszystkie wrogie instalacje. +1| + +@20 +1|Solucja: +1| +1|Stwórz tyle dynamitu, pułapek itd. +1|ile to tylko możliwe zanim zniszczysz +1|bariery chroniące obóz. + +#21 +1|Sytuacja: +1| +1|Blupi został porwany przez +1|roboty. Teraz jest więźniem +1|w obozie robotów. + + + + + +2|Cel: +2| +2|Blupi musi uciec i znaleźć +2|drogę do domu. + +@21 +1|Solucja: +1| +1|Weź dynamit z północnego +1|wschodu. Połóż go obok nie- +1|bieskiej bariery od strony dziury +1|niedaleko skał. Przejeżdżający +1|buldożer spowoduje eksplozję. +1|To powinno zniszczyć barierę. + +2|Idź na wschód dopóki nie trafisz +2|na rzekę. Stwórz łódź z desek. +2|Będziesz potrzebować też drugiej +2|sterty desek by zbudować później +2|drugą łódź. Zanim to zrobisz, +2|musisz złapać paralizatora w +2|klejącą pułapkę i stworzyć bombę +2|zegarową w celu zniszczenia +2|niebieskiej bariery na wschodzie. + +#22 +1|Cele: +1| +1|1) Stwórz łódki. +1| +1|2) Eksploruj wszystkie wyspy. +1| +1|3) Zniszcz wszystkie wrogie +1|instalacje + +@22 +1|Solucja: +1| +1|Wyspa na północnym wschodzie +1|ma mnóstwo żelaza. + +2|Wyspa na wschodzie ma wszystko +2|co potrzebne by stworzyć dynamit +2|i klejące pułapki. + +#23 +1|Sytuacja: +1| +1|Blupi jest bardzo ciekawski: +1|śledził robota przez dłuższy +1|czas zanim uświadomił sobie +1|że się zgubił. + + + + + +2|Cel: +2| +2|Zorganizuj wsparcie i zniszcz +2|wroga! + + +@23 +1|Solucja: +1| +1|Samotny Blupi musi oddalić się +1|od robota i iść na zachód. Blupi +1|musi skuć skałę by mieć dostęp +1|do drzew a następnie stworzyć +1|teleporter. + + +2|Druga grupa Blupich musisz +2|zbudować łódź, znaleźć +2|bombę na północnym wschodzie, +2|a następnie wysadzić barierę +2|na południu. To da ci dostęp +2|do drewna które musisz przeniść +2|na poprzednią wyspę by zbudować +2|teleporter pozwalający ci na +2|uratowanie zagubionego Blupiego. + +#24 +1|Sytuacja: +1| +1|Region jest pełen wrogów. +1| + + + +2|Cel: +2| +2|Zniszcz wszystkich wrogów. + +@24 +1|Solucja: +1| +1|Idź na południowy wschód +1|by uciec przed pożarem i stwórz +1|łódź z jedynego ocalałego drzewa. +1| +1|W obozie znajdziesz trochę żelaza. + +2|Na północy obozu znajdziesz trochę +2|jaj. + +#25 +1|Blupi podejrzewa że roboty +1|przyniosły coś dziwnego na +1|jego planetę: +1| +1| Platynę.... +1| +1|Platyna, leżąca obok wrogiej +2|rakiety da mu dostęp do +2|technologii przeciwnika. +2| + + +2|Cel: +2|Dostarcz kostkę platyny +2|na nawierzchnię docelową. + +@25 +1|Solucja: +1| +1|Zneutralizuj 2 buldożery za +1|pomocą klejących pułapek. Stwórz +1|łódź na północ od pierwszego +1|wrogiego obozu, zaokrętuj razem +1|z bombą zegarową i udaj się na +1|wschód. +1| +1|Znajdź ścieżkę między skałami +1|prowadzącą na południe. +2|Wrogi obóz z rakietą jest daleko +2|jest daleko na wschodzie. Musisz +2|wysadzić barierę by móc dotrzeć +2|do platyny. +2| +2| +2|Przynieś platynę do własnego +2|obozu. + +#26 +1|Kostka platyny daje ci dostęp +1|do wrogiej technologii, więc +1|wykorzystaj ją dobrze. + + + + + +2|Cel: +2| +2|Pomóc Blupiemu znaleźć swój dom. + +@26 +1|Solucja: +1| +1|Stwórz robota pomocnika za +1|pomocą kostki platyny w fabryce +1|i stwórz bombę zegarową. +1| +1|Weź robota i bombę. Robot może +1|przekroczyć wrogi obóz na +1|zachodzie bez przeszkód. Wysadź +1|barierę na północy i weź +1|pomidory by nakarmić +1|Blupiego w swoim obozie. +2| +2|Połóż pomidory na ziemi zanim +2|wykonasz skok. + +#27 +1|Sytuacja: +1| +1|Robot miał czelność założyć +1|swoją osadę niedaleko wioski +1|Blupich. + + + + +2|Cel: +2| +2|Znajdź wrogi obóz +2|i zniszcz wszystko. + +@27 +1|Solucja: +1| +1|Stwórz teleporter tak szybko +1|jak to możliwe, dzięki czemu +1|uzyskasz dostęp do wyspy +1|z jajami. Zbuduj dwie wieże +1|ochronne w miejscu sterty +1|kamieni. Zbuduj palisady po +1|lewej i prawej stronie każdej +1|wieży. + +2|Teraz możesz złapać oddech! +2| +2|Masz dwie możliwości dotarcia +2|do wrogiego obozu na północy, +2|popłynąć tam łódką lub +2|zbudować most. +2| +2|Wybór należy do ciebie! + +#28 +1|Sytuacja: +1| +1|Podczas budowy swojego +1|domu Blupi strzelił gafę: +1|zbudował wokół niego mur. + + + + + +2|Cel: +2| +2|Blupi musi dotrzeć do swojego +2|domu. + +@28 +1|Solucja: +1| +1|Mała wyspa na północy +1|ma wiele jaj. +1| +1|Musisz przekroczyć wrogi obóz +1|tak szybko jak to możliwe +1|by uniknąć spotkania z buldo- +1|żerami zmierzających z północy +1|oraz południa, żebyś mógł zebrać +2|niebieskie kwiaty. +2|Inny Blupi może je zabrać by +2|stworzyć dynamit. +2| +2|Jedyne skały które mogą być +2|wykorzystane są na południe +2|wrogiego obozu, na zewnątrz +2|muru obronnego. + +#29 +1|Sytuacja: +1| +1|Robot i jego akoloci zajmują +1|coraz więcej wolnej przestrzeni. + + + + + +2|Cel: +2| +2|Blupi musi zbudować wioskę +2|i opracować dobrą taktykę +2|obronną. +2| +2|Następnie zaatakuje i wyeliminuje +2|wszystkich wrogów. + +@29 +1|Solucja: +1| +1|Blupi musi zbudować wieże +1|ochronne na północno-zachodniej +1|stronie, północno wschodniej +1|oraz południowo wschodniej. +1|Wszystkie skały są na północno-. +1|zachodniej stronie. +1| +1|Nie ścinaj drzew przy palisadach. +1|Mogą okazać się przydatne +1|w starciu ze skaczącymi bombami! + +2|Zielone kwiaty na wschodzie +2|pozwolą ci stworzyć klejące +2|pułapki by obronić wioskę. +2| +2|Wydobądź żelazo na południowym +2|zachodzie i stwórz bomby i +2|pancerze. + +#30 +1|Sytuacja: +1| +1|Czas zakończyć tą wojnę. +1|Blupi i ostatni z robotów osiągnęli +1|porozumienie: +1|Blupi pomoże robotom wrócić do +1|rakiety, w zamian roboty ostatec- +1|cznie opuszczą planetę Blupiego. + + + + +2|Cel: +2| +2|Przygotuj ścieżkę do rakiety +2|by umożliwić robotowi opuszczenie +2|planety. Porażka tak dotknęła +2|robota, że ten odmawia ruszenia się +2|z miejsca zanim ścieżka zostanie +2|ukończona. + +@30 +1|Solucja: +1| +1|Wykuj skałę na południowym +1|wschodzie. Zetnij drzewo i stwórz +1|łódź. Będąc w łodzi, poszukaj wyspy +1|na północnym wschodzie. Znajdź +1|żelazo, stwórz kopalnię i fabrykę. +1|Stwórz bombę za pomocą której +2|wysadzić bariery wokół robota. +2| +2|Teraz musisz tylko zbudować most +2|który zaprowadzi robota wprost +2|do jego rakiety. diff --git a/resources/data/pt/stories.blp b/resources/data/pt/stories.blp new file mode 100644 index 0000000..138d639 --- /dev/null +++ b/resources/data/pt/stories.blp @@ -0,0 +1,1144 @@ +$1 +1|Objetivo: +1| +1|Cada Blupi deve entrar em uma casa. +1|Para fazer isso, sempre use o botao +1|esquerdo do mouse. + +2|1) Clique em um Blupi. +2| Um anel vai aparecer em volta +2| dele indicando que esta selecionado. +2| +2|2) Clique em sua casa. +2| +2|3) Clique em "Ir" +2| +2|4) Repita esses passos para +2| o segundo Blupi. + + + + + + + + + + Depois de ter lido esses passos + clique no dado abaixo para jogar. + +$2 +Existe um segundo treino um pouco mais +complicado: + +1|Transportar ambas pilhas de madeiras +1|para o pavimento de pedra na +1|direita. +1| +1|Blupi deve comer tomates para +1|acumular energia suficiente para +1|fazer isso. Note que +2|quando ele come, o anel vermelho +2|torna-se azul. Isso +2|indica seu nivel de energia. +2| +2| vermelho = cansado +2| azul = energia + + + +Dica: +Para arrastar sua tela, você pode +arrastar seu mouse para o lado da +tela ou usar as setas do seu +teclado. + +$3 +1|Encontre os ovos ... +1| +1|Colocando-os na incubadora, +1|quatro novos Blupis +1|nascerao dos ovos. + + + + + + +Dica: +é mais eficiente usar +o mouse e o teclado +ao mesmo tempo. + +$4 +1|Objetivo: +1| +1|Os quatro Blupis devem chegar nas +1|casas ao norte da ilha. + +2|Cada Blupi deve comer para ter +2|energia suficiente para pular. + +$5 +1|Objetivo: +1| +1|Colocar dois grupos de tomates +1|no pavimento de pedra. + +2|Para isso você deve cortar as +2|plantas e construir uma casa do +2|jardim, plantar os tomates e +2|depositar dois grupos de tomates +2|no pavimento de pedra (sem comer). + +$6 +1|Objetivo: +1| +1|Cada Blupi deve chegar em casa +1|em uma pequena ilha. +1|Infelizmente existe comida suficiente +1|para apenas um Blupi. +2|Você vai precisar encontrar uma +2|forma de produzir comida suficiente +2|para todos os outros. +2| +2|Felizmente, a ilha possui +2|muitas plantas. + +#h1 +A vida do Blupi em seu planeta +era perfeita. Tudo era muito +bonito e quieto até que um dia +um estranho meteorito caiu em +um local remoto. + +Algum tempo depois, Blupi +percebeu que sua colheita +estava sendo devastada por +aranhas gigantes. + +E ainda parece que apesar da sua +excelente forma fisica, Blupi +pegou uma curiosa doença. +Ele agora espirra e tosse bastante. + +#h2 +O que esta acontecendo? + +Bem, o estranho meteorito parece +ser uma nave espacial. Restou +somente um sobrevivente na +batida, e parecer ser um robo. +E a unica coisa que ele quer é +construir fabricas para produzir +todo tipo de maquinas perversas +para acabar com o planeta do +Blupi. + +O Blupi precisa da sua ajuda e +habilidade para obter uma +vantagem de todos os recursos +naturais para se livrar desses +intrusos... + +#1 +A nave espacial colocou fogo na +floresta. Agora a vila do Blupi +pode estar em perigo. + +1|Objetivo: +1| +1|Impedir que a vila seja queimada. +1|Para fazer isso, existe apenas uma +1|maneira: Cortar algumas plantas +1|do lado esquerdo. + + + + + +2|Dica: +2| +2|Se um Blupi ficar escondido atras +2|de uma planta, pressione a barra +2|de espaço. Fazendo isso ele vai +2|aparecer transparente por alguns +2|instantes. + +@1 +1|Soluçao: +1| +1|Levar o Blupi para a esquerda +1|para cortar algumas plantas. Os +1|dois outros Blupis podem +1|carregar as madeiras. + +#2 +1|Objetivo: +1| +1|Blupi esta longe e perdido da +1| sua vila. Ele deve se organizar +1|antes de procurar pela vila. +1| +1|1) Construa uma casa do jardim e +1| plante tomates. + +2|2) Construa uma incubadora para +2| obter ajuda. +2| +2|3) Alimente os quatro Blupis e +2| procure pela vila. +2| + + +2|Tenha cuidado: +2| +2|Algumas coisas incomuns +2|podem acontecer. + + +@2 +1|Dicas: +1| +1|Primeiro, você deve construir +1|duas barreiras no norte +1|para parar a aranha. +1|Somente assim sera possivel +2|construir uma casa do jardim +2|e plantar tomates em paz. +2| +2|Para alcançar as quatro casas +2|você deve comer. + + +#3 +1|Objetivo: +1| +1|Evitar que os quatro Blupis +1|se queimem. +1| +1|Termine a parede. + + + + +2|Tenha cuidado: +2| +2|O terreno é feito de musgo +2|que queima mais facilmente. + +@3 +1|Soluçao: +1| +1|1) Esculpir uma pedra. +1| As pedras menores ficam +1| prontas rapidamente. + +2|2) Construa uma parede entre +2| as outras duas. +2| +2|3) Espere até que o fogo acabe. + +#4 +1|Objetivo: +1| +1|Faça os quatro Blupis +1|alcançarem o pavimento +1|de pedra + +@4 +1|Soluçao: +1| +1|1) Corte uma planta +1| +1|2) Leve as madeiras para +1| perto da margem. +1| +1|3) Construa uma ponte entre +1| os dois Blupis cansados. + +2|4) Repita estes passos +2| três vezes. +2| +2|Os Blupis cansados podem +2|atravessar a ponte e alcançar +2|o pavimento de pedras. + +#5 +1|A armadilha: +1|Cuidado, o terreno onde os +1|Blupis estao prisioneiros +1|podem se queimar. +1| +1|Objetivo: +1| +1|Resista até quando o fogo +1|tiver apagado. + +2|Tome Cuidado: +2|Construir uma parede é trabalho +2|muito cansativo para o Blupi. +2|Quando ele terminar, vai morrer ! + + + +Dica: +Se o jogo estiver muito devagar +para você, pressione a tecla F6 +para aumentar a velocidade. E +F5 para voltar ao normal. + +@5 +1|Dicas: +1| +1|Você deve construir quatro +1|paredes no pavimento cinza. +1|Você vai ter que cortar duas +1|plantas para construir uma casa +1|do jardim e uma incubadora. + +2|Quando as paredes estiverem +2|terminadas, você vai ter que +2|esperar até o fogo acabar. + +#6 +1|Objetivo: +1| +1|Um perigo esta presente: proteja +1|o campo o mais depressa possivel +1|com quatro torres. + +2|Agora você pode juntar +2|os pavimentos de pedra no +2|sudeste. + + + + + + + + + +Dica: + +Você pode selecionar muitos Blupis +ao mesmo tempo mantendo +a tecla shift pressionada enquanto +clica em cada Blupi. + + +@6 +1|Soluçao: +1| +1|Você deve colocar quatro Blupis +1|para esculpir as pedras +1|rapidamente. As menores ficam +1|prontas mais rapidamente. +1| +1|Transporte as quatro pilhas de +1|pedras para o pavimento cinza +1|escuro e comece a construir +1|as torres de proteçao. + +2|Espere pela chegada e +2|destruiçao dos virus. +2| +2|Os outros quatro Blupis +2|podem ir rapidamente para +2|o pavimento de pedra no +2|sudeste. + +#7 +1|Objetivo: +1| +1|Os quatro Blupis devem +1|alcançar o pavimento de +1|pedras. Você devera tomar +1|cuidado com o Blupi +1|mais distante. + + + + + +2|Tome cuidado: +2| +2|O terreno é inapropriado +2|para construir uma casa do +2|jardim. + +@7 +1|Soluçao: +1| +1|Faça um Blupi guardar um +1|tomate rapidamente para que +1|as aranhas nao o comam. +1| +1|Com outro Blupi, pule na +1|outra ilha e construa uma ponte +1|que vai ligar as duas ilhas. + +2|Carregue os tomates para o +2|Blupi casado para que ele +2|possa comer. + +#8 +1|Objetivo: +1| +1|Evitar que um ou dois Blupis +1|se contaminem e encontrar um +1|remedio para curar os outros. +1| +1|Finalmente cada Blupi deve +1|entrar em uma casa. + + + + + + + +2|Dica: +2| +2|Construa um laboratorio. + +@8 +1|Soluçao: +1| +1|Um laboratorio de pedra deve +1|ser feito. Ele vai permitir que +1|você transforme as flores +1|amarelas em remedio para +1|curar os Blupis. + +2|Você precisa construir uma +2|ponte para levar o remedio +2|para curar os Blupis. +2| +2|As casas ficam no sudeste da ilha. + +#9 +1|Objetivo: +1| +1|Encontrar uma forma para +1|atravessar a pista de gelo. + + + + + + +2|Nota: +2| +2|Blupi pode andar no gelo. Mas +2|como o gelo é muito escorregadio, +2|ele vai perder muita energia. + +@9 +1|Soluçao: +1| +1|Construa duas torres para +1|proteger os Blupis das +1|aranhas. +1| +1|Você precisa construir uma casa +1|do jardim e uma incubadora +1|para deixar os ovos chocarem. + +2|Blupi perde muita força +2|quando ele atravessa a pista +2|de gelo. Portanto, você deve +2|levar os tomates antes da pista. + +#10 +1|Objetivo: +1| +1|Alcançar a ilha no +1|nordeste e explodir +1|uma barreira. + +2|Tudo o que você precisa fazer +2|agora é colocar os quatro +2|Blupis no pavimento de pedra. + +@10 +1|Soluçao: +1| +1|Construa uma ponta na direçao +1|dos quatro prisioneiros. Você pode +1|esculpir uma pedra para +1|construir um laboratorio. +1| +1|As flores azuis podem ser +1|encontradas no sudeste. +1|Levando-as para o laboratorio, +1|elas podem ser transformadas +1|em dinamite. + +2|Use a dinamite para destruir +2|a barreira que esta prendendo +2|os quatro prisioneiros Blupis. +2| +2|Primeiro, você precisa +2|afastar os prisioneiros para +2|protegê-los da explosao. + +#11 +1|Objetivo: +1| +1|Alcançar as casas no +1|nordeste. Tome cuidado, +1|elas estao bem guardadas. + +@11 +1|Dicas: +1| +1|Construa uma ponte no sentido +1|da ilha noroeste e depois +1|faça pelo menos quatro pacotes +1|de dinamite. + +2|Coloque as dinamites no +2|norte corretamente perto das +2|escavadoras. +2| +2|Enquanto as dinamites nao +2|estiverem prontas, evite ir +2|ao norte ou você sera atacado +2|pelas escavadoras. + +#12 +1|Objetivo: +1| +1|Três Blupis devem se unir +1| com o Blupi isolado na ilha +1|no lado noroeste. + +@12 +1|Dica: +1| +1|Construa uma casa do jardim +1|e plante tomates. +1| +1|Faça dinamites com as flores +1|azuis que podem ser +1|encontradas no nordeste. + +2|Transporte as dinamites para +2|a ilha situada no oeste. +2| +2|Tome cuidado, o caminho possui +2|dois virus escondidos. + +#13 +1|Objetivo: +1| +1|Conseguir se livrar das seis +1|aranhas. +1| +1|As quatro primeiras serao +1|faceis. As duas restantes +1|serao mais dificeis. + + + + + + +2|Dica: +2| +2|Descubra como produzir +2|remedio no laboratorio. + +@13 +1|Soluçao: +1| +1|As primeiras quatro aranhas +1|podem ser capturadas com +1|armadilhas feitas com as flores +1|verdes no laboratorio. +1| +1|As armadilhas devem ser +1|colocadas perto das aranhas. + +2|As outras duas podem ser +2|com os tomates que foram +2|alterados no +2|laboratorio. +2| +2|Construa uma ponte para carregar +2|os tomates para o laboratorio. + +#14 +1|Objetivo: +1| +1|O Blupi deve simplesmente +1|ir para casa. +1| + +@14 +1|Soluçao: +1| +1|Procure por ferro sobre o +1|terreno rochoso. Coloque uma +1|madeira na bandeira e +1|construa uma mina. +1| +1|Esculpa uma rocha para construir +1|uma oficina aonde você vai +1|poder utilizar o ferro. + +2|Pegue a bomba, suba no +2|jeep e ande para o leste. +2|O jeep vai te proteger das +2|escavadoras. +2| +2|Quando você chegar na barreira, +2|você deve deixar o seu jeep +2|rapidamente, deixar a bomba , +2|liga-la, entrar no jeep e +2|fugir + +#15 +1|Objetivo: +1| +1|Somente um Blupi +1|deve alcançar a casa no +1|nordeste. + +2|Para fazer isso, você deve +2|destruir as diversas +2|instalaçoes inimigas. + +@15 +1|Dicas: +1| +1|Construa uma casa do jardim +1|e duas torres no pavimento +1|cinza escuro. +1| +1|Construa uma ponte para ligar +1|a ilha ao leste. Selecione +1|diferentes tipos de flores e as +1|traga para o campo. + +2|Construa um laboratorio, faça +2|dinamites e armadilhas pegajosas. +2|Proteja o campo com as +2|armadilhas pegajosas e +2|fora com as dinamites. +2| +2|Quando você achar que possui +2|dinamites e armadilhas suficientes, +2|mande um pequeno comando para +2|o nordeste de destrua o campo +2|inimigo + +#16 +1|Situaçao: +1| +1|Blupi esta perdido em uma parte +1|arida do planeta sem nenhuma +1|planta. + + + + +2|Objetivo: +2| +2|Os dois Blupis devem voltar +2|para casa em sua vila. + +@16 +1|Dicas: +1| +1|Encontre a mina no nordeste, +1|esculpa uma rocha e construa +1|uma oficina, faça uma bomba +1|e dois jeeps, e procure o +1|campo inimigo no sudoeste. + +2|Exploda a barreira no campo +2|inimigo. Tente explodir junto +2|as escavadoras. +2| +2|Você deve ir para o sul e +2|procurar pela planta e fazer +2|um teletransportador. + +#17 +1|Objetivo: +1| +1|Os cinco Blupis devem +1|alcançar uma casa. + +2|Cuidado, uma casa fica +2|atras do campo inimigo. + + + + + + + + + + + + +Dica: + +Você pode selecionar alguns +Blupis ao mesmo tempo +mantendo a tecla Shift selecionada +enquanto clica em cada Blupi. + +@17 +1|Soluçao: +1| +1|Um Blupi pode ir para a casa +1|no lado oeste da ilha. +1|Os outros quatro devem ir embora +1|rapidamente por causa das +1|escavadoras. Os Blupis +1|devem ir para o nordeste. + +2|Mais adiante, você deve encontrar +2|uma vila cercada por barreiras. +2| +2|No norte da ilha, existe muito +2|ferro. +2| +2|Você deve fazer um bote e ir +2|para o nordeste da ilha com +2|uma bomba. + +#18 +1|Situaçao: +1| +1|Enquanto Blupi estava +1|colhendo flores, ele nao percebeu +1|que estava perdido da sua +1|casa. Agora ele esta perdido +1|em um lugar cheio de inimigos. + + + + + +2|Objetivo: +2| +2|Blupi deve fugir e encontrar +2|uma forma para voltar para casa. + +@18 +1|Dicas: +1| +1|Encontre a agua localizada no +1|oeste. Faça um bote. Cuidado, +1|pode pode encontrar muitos +1|virus espalhados em volta. + +2|Com o bote, você pode +2|atravessar e desembarcar +2|na margem. +2| +2|A casa esta perto agora. Tenha +2|cuidado, você deve evitar +2|as escavadoras. + +#19 +1|Situaçao: +1| +1|Quatro escavadoras parecem +1|ameaçando a vila do Blupi. + + + + + +2|Objetivo: +2| +2|Destruir as escavadoras + +@19 +1|Dicas: +1| +1|Faça um Blupi extrair ferro +1|e construir uma armadura. Ela vai +1|pretegê-lo do fogo. +1| +1|Ande para o leste e construa um +1|bote. Embarque e procure por +1|outra ilha com planta. Corte a +1|planta e coloque a madeira +2|na ilha maior. Faça um +2|teletransportador. Ele vai te levar +2|para a fortaleza. +2| +2|Coloque algumas dinamites perto +2|das paredes e exploda-as +2|Com o restante das +2|dinamites, você pode destruir +2|as escavadoras. + +#20 +1|Objetivo: +1| +1|Destruir todas as instalaçoes +1|inimigas. +1| + +@20 +1|Dicas: +1| +1|Produza muitas dinamites, +1|armadilhas, etc. possiveis antes +1|de explodir as barreiras que +1|protegem o campo inimigo. + +#21 +1|Situaçao: +1| +1|Blupi foi capturado por um +1|robo asqueroso. Ele é um +1|prisioneiro na base de campo +1|do robo. + + + + +2|Objetivo: +2| +2|Blupi deve escapar e achar +2|sua casa. + +@21 +1|Dicas: +1| +1|Pegue a dinamite do nordeste. +1|Coloque-a perto da barreira +1|azul no espaço vazio nas +1|rochas. Quando as escavadoras +1|passarem pelas dinamites, elas +1|podem destruir as barreiras. + +2|Corra para o leste ate alcançar +2|o rio. Faça um bote com as +2|plantas. Você vai precisar de +2|uma segunda pilha de madeiras +2|para construir um bote depois. +2|Antes disso, você vai ter que +2|pegar o eletrocondutor com +2|a armadilha pegajosa e fazer +2|uma bomba para destruir a +2|barreira azul no leste. + +#22 +1|Objetivo: +1| +1|1) Fazer botes. +1| +1|2) Explorar toda a ilha. +1| +1|3) Destruir todas instalaçoes +1| inimigas. + +@22 +1|Dicas: +1| +1|A ilha no nordeste tem +1|muito ferro. + +2|A ilha no leste tem tudo o +2|que você precisa para fazer +2|dinamite e armadilhas pegajosas. + +#23 +1|Situaçao: +1| +1|Blupi parece estar curioso. +1|Depois de ter observado o robo +1|por um longo tempo, ele percebe +1|agora que ele esta perdido. + + + + +2|Objetivo: +2| +2|Trazer ajuda e destruir +2|os inimigos! + + +@23 +1|Dicas: +1| +1|O Blupi isolado deve ir +1|longe do robo e ir para o +1|leste. Blupi deve esculpir +1|uma rocha para permitir +1|alcançar a madeira, e entao +1|fazer um teletransportador. + +2|Com o segundo grupo de +2|Blupis, você deve fazer um +2|bote, encontrar a bomba no +2|nordeste e explodir a barreira no +2|sul. Isto vai permitir você trazer +2|a madeira para perto da ilha +2|e fazer um teletransportador para +2|permitir você se unir e ajudar +2|o Blupi perdido. + +#24 +1|Situaçao: +1| +1|O lugar possui muitos inimigos. +1| + + + +2|Objetivo: +2| +2|Destruir todos os inimigos. + +@24 +1|Dicas: +1| +1|Vai para o sudeste para evitar +1|o fogo e faça um bote com +1|uma planta restante. +1| +1|No campo, você vai encontrar +1|algum ferro. + +2|No norte do campo, você vai +2|encontrar alguns ovos. + +#25 +1|Blupi ficou desconfiado +1|porque o trouxe algumas +1|coisas estranhas para o +1|seu planeta: +1| +1| Platina.... +1| +1|A platina, que foi colocada +2|perto do foguete do robo, +2|vai dar acesso à tecnologia +2|do inimigo. +2| + + +2|Objetivo: +2| +2|Trazer cubo de platina para +2|o pavimento de pedra. + +@25 +1|Soluçao: +1| +1|Destruir duas escavadoras com +1|armadilhas pegajosas. Fazer um +1|bote no norte do primeiro campo +1|inimigo, depois embarcar com uma +1|bomba e ir para o leste. +1| +1|Procurar por um caminho entre as +1|rochas indo para o sul. O campo +2|inimigo com o foguete esta +2|longe do leste. Você vai precisar +2|explodir uma barreira para +2|permitir pegar e carregar a +2|platina. +2| +2|Traga a platina de volta +2|para a base. + +#26 +1|O cubo de Platina vai permitir +1|você acessar a tecnologia inimiga +1|para usa-la corretamente. + + + + + +2|Objetivo: +2| +2|Ajudar o Blupi a encontrar a +2|sua casa. + +@26 +1|Dicas: +1| +1|Fazer um robo ajudante com o +1|cubo de platina na fabrica e +1|fazer uma bomba. +1| +1|Pegar o robo e a bomba. +1|O robo pode cruzar o oeste +1do campo inimigo sem ser +2|notado. Exploda a barreira +2|no norte e pegue os tomates +2|para alimentar o Blupi +2|no campo. +2| +2|Largue os tomates antes de +2|pular. + +#27 +1|Situaçao: +1| +1|O robo teve o atrevimento de +1|instalar a sua vila perto da +1|vila do Blupi. + + + + +2|Objetivo: +2| +2|Alcançar o campo inimigo e +2|destruir tudo. + +@27 +1|Dicas: +1| +1|Fazer um teletransportador o +1|mais rapido possivel para você +1|alcançar a ilha com os ovos. +1|Construir duas torres nas +1|pedras na cor cinza escuro. +1|Construir uma barreira na +1|esquerda e direita de cada +1|torre. + +2|Agora você pode respirar ! +2| +2|Você tem duas formas para +2|alcançar o campo inimigo no +2|norte, pelo bote ou +2|construindo uma ponte. +2| +2|Você pode escolher ! + +#28 +1|Situaçao: +1| +1|Enquanto estava construindo +1|sua casa, Blupi fez um erro: +1|ele construiu uma parede em +1|volta dela. + + + + + +2|Objetivo: +2| +2|Blupi deve simplesmente +2|ir para casa. + +@28 +1|Dicas: +1| +1|Uma pequena ilha no norte +1|tem muitos ovos. +1| +1|Você precisa atravessar o +1|campo inimigo rapidamente +1|para evitar que as +1|escavadoras venham do +1|norte e do sul, para que +2|você possa colher +2|flores azuis. +2|Outro Blupi pode pega-las +2|para fazer dinamites. +2| +2|Você vai poder usar somente +2uma rocha que esta no campo +2|inimigo, simplesmente fora +2|da parede de proteçao. + +#29 +1|Situaçao: +1| +1|O espaço livre parece estar sendo +1|ocupado mais e mais pelo robo +1|e seus ajudantes. + + + + + +2|Objetivo: +2| +2|Blupi deve construir sua vila +2|e elaborar uma boa tatica +2|de defesa. +2| +2|Ele vai ter que atacar e +2|eliminar todos os seus inimigos. + +@29 +1|Dicas: +1| +1|Ele deve construir torres de +1|proteçao no noroeste, +1|nordeste e no lado sudeste. +1|Todas as rochas podem ser +1|encontradas no noroeste. +1| +1|Deixe as plantas perto das +1|barreiras. Elas podem ser +1|utilizadas contra as bombas ! + +2|As flores verdes no leste permitem +2|você fazer armadilhas pegajosas +2|para defender a vila. +2| +2|Extraia ferro no sudoeste e faça +2|bombas e armadilhas. + +#30 +1|Situaçao: +1| +1|Esta guerra precisa acabar logo. +1|Blupi e o robo tiveram que +1|fazer um acordo: +1|Ele precisa ajudar o robo a voltar +1|para o seu foguete, em retorno, +1|o robo vai deixar de forma +1|definitiva o planeta do Blupi. + + + + +2|Objetivo: +2| +2|Preparar o caminho para o +2|foguete para que o robo possa +2|deixar o planeta. Tendo perdido +2|a batalha, o robo ficou zangado +2|e se recusa a se mover até que +2|o caminho esteja terminado. + +@30 +1|Dicas: +1| +1|Esculpa uma rocha no sudeste. +1|Corte uma planta e faça um bote. +1|Com o bote, procure por uma +1|ilha no nordeste. +1|Procure por algum ferro, construa +1|uma mina e uma fabrica. Faça uma +2|bomba, que vai permitir você +2|explodir as barreiras em volta do +2|do robo. +2| +2|Tudo o que você precisa, seria +2|construir uma ponte para que o +2|robo possa voltar ao seu foguete. diff --git a/resources/data/tr/stories.blp b/resources/data/tr/stories.blp new file mode 100644 index 0000000..d7a5985 --- /dev/null +++ b/resources/data/tr/stories.blp @@ -0,0 +1,1096 @@ +$1 +1|Hedef: +1| +1|Her Blupi bir eve girmek zorunda. +1|Bunu yapmak için, her zaman sol +1|fare tuşunu kullan. + +2|1) Bir Blupi'ye tıkla +2| Onun etrafında, seçildiğini +2| gösteren mavi bir halka +2| belirecek. +2| +2|2) Onun evine tıkla +2| +2|3) "git" butonuna bas +2| +2|4) İkinci Blupi için aynı +2| işlemleri tekrar et. + + + + + + + + Bu yönergeleri okuduktan sonra, + aşağıdaki zara bas. + +$2 +İşte daha karışık olan ikinci +alıştırma: + +1|Her iki kalas yığınını sağdaki +1|çizgili parke taşına taşı. +1| +1|Blupi, bu işlem sırasında +1|yeterli güç toplamak için +1|domates yemeli. Öyle ki, onları +2|yediği zaman, ayağındaki +2|kırmızı halka maviye dönüşür. Bu +2|onun enerji seviyesini gösterir. +2| +2| kırmızı = bitkin +2| mavi = formda + + + +İpucu: +Ekranı kaydırmak için, fareni +ekranın kenarına çekebilir +veya klavye yön tuşlarını +kullanabilirsin. + +$3 +1|Yumurtaları bul ... +1| +1|Onları inkübatöre koyduktan +1|sonra, dört yeni Blupi +1|yumurtadan çıkacak. + + + + + + +İpucu: +Bir elle fareyi kullanırken +diğeriyle klavye yön oklarını +kullanmak daha etkili. + +$4 +1|Hedef: +1| +1|Dört Blupi kuzeydeki adalarda +1|bulunan evlere ulaşmalı. + +2|Her Blupi, zıplamak için gereken +2|gücü almak için yemek yemeli. + +$5 +1|Hedef: +1| +1|İki grup domatesi çizgili +1|parke taşının üzerine koy. + +2|Bunu yapmak için, ağaçları +2|kesmelisin, bir bahçe kulübesi +2|inşa etmelisin, domates +2|yetiştirmelisin ve iki grup +2|domatesi çizgili parke taşının +2|üzerine koymalısın (onları sakın +2|yeme). + +$6 +1|Hedef: +1| +1|Her Blupi, küçük bir adada +1|bulunan bir eve ulaşmalı. +1|Ne yazık ki, burada sadece tek +1|Blupi'ye yetecek kadar yemek var. +2|Senin hepsine yetecek kadar +2|yemek üretmek için bir yol +2|bulman lazım. +2| +2|Neyse ki, adada bir sürü ağaç +2|var. + +#h1 +Blupi, adasında sessizce +yaşamaktayken, garip bir göktaşı +kurak bir alana düşer. + +Hemen ardından, Blupi, ekinlerinin +iri örümcekler tarafından tahrip +edildiğini farkeder. + +Blupi, kusursuz formuna rağmen, +ciddi bir hastalığa yakalandı ve +şimdi hapşırmakta. + +#h2 +Neler oluyor burada? + +Aslında tuhaf göktaşı, çok özel +bir robot taşıyan uzay gemisi. + +Bu robot düşman üreten fabrikalar +inşa ediyor. + +Blupi bu davetsiz misafirlerden +kurtulmak için bütün doğal +kaynakları kullanmalı. + +#1 +Uzay gemisi çarpışması ormanda +yangın çıkardı. Blupi'lerin +köyü şimdi tehlikede. + +1|Hedef: +1| +1|Köyün yanmasını engelle. +1|Bunu yapmak için sadece bir yol +1|var: +1|Solda bulunan ağaçların +1|bazılarını kes. + + + + + + +2|İpucu: +2| +2|Eğer bir Blupi ağaçların arkasına +2|gizlenmişse, boşluk tuşuna bas. +2|Bunu yapmak, ağaçları geçici +2|olarak saydam hale getirecek. + +@1 +1|Çözüm: +1| +1|Soldaki Blupi'ye birçok ağacı +1|kesmesi için buyur. Diğer iki +1|Blupi kalasları uzağa taşıyacak. + +#2 +1|Durum: +1| +1|Blupi köyünden uzakta ve +1|kayboldu. O, köyünü aramadan +1|önce düzen kurmalı. +1| +1|1) Bir bahçe kulübesi inşa et ve +1| domates yetiştir + +2|2) Destek kazanmak için bir +2| inkübatör inşa et. +2| +2|3) Dört Blupi'yi besle ve köyü +2| bulmaya git. +2| + + +2|Dikkat et: +2| +2|Sıradışı bir şey olacak. + + +@2 +1|İpuçları: +1| +1|Öncelikle, örümceğin gelmesini +1|engellemek için kuzeye iki +1|kazıklı çit inşa etmelisin. +1|Ancak o zaman, huzur içinde +2|bir bahçe kulübesi inşa +2|edebileceksin ve domates +2|yetiştirebileceksin. +2| +2|Dört eve ulaşmak için, doğuya +2|gitmelisin. + + +#3 +1|Hedef: +1| +1|Dört kayıp Blupi'nin yanmasını +1|engelle. +1| +1|Duvarı bitir. + + + + +2|Dikkat et: +2| +2|Zemin, kolay yanabilen +2|yosunlardan ibaret. + +@3 +1|Çözüm: +1| +1|1) Kaya kes. +1| Ufak kayaları kesmek daha +1| hızlı. + +2|2) İki mevcut duvar arasına +2| yeni bir duvar inşa et. +2| +2|3) Yangının durmasını bekle. + +#4 +1|Hedef: +1| +1|Dört Blupi'nin çizgili parke +1|taşına ulaşmasını sağla. + +@4 +1|Çözüm: +1| +1|1) Bir ağaç kes. +1| +1|2) Kalasları suyun kenarına +1| taşı. +1| +1|3) İki bitkin Blupi'ye doğru +1| bakan bir köprü inşa et. + +2|4) Bu işlemi üç kere tekrarla. +2| +2|Bitkin Blupi'ler şimdi +2|köprüden geçip çizgili parke +2|taşına ulaşabilir. + +#5 +1|Tuzak: +1|Dikkat, Blupi'lerin esir +1|olduğu toprak kolayca alev +1|almakta ve yangın daha da +1|yaklaşmakta. +1| +1|Hedef: +1|Yangın sönene kadar dayan. + +2|Dikkat et: +2|Duvar yapmak Blupi için çok +2|yorucu bir iş. Duvarı +2|bitirdiğinde, Blupi ölür ! + + + +İpucu: +Eğer oyun senin için yeterince +hızlı değilse, oyunu +hızlandırmak için F6'ya bas. +F5, oyunu normal hızda +çalıştırır. + +@5 +1|İpuçları: +1| +1|Gri parke taşlarının üzerine +1|dört duvar inşa etmelisin. +1|Bir bahçe kulübesi ve +1|inkübatör inşa etmek için +1|iki ağaç kesmelisin. + +2|Duvarlar bittiğinde, yangın +2|durana kadar beklemelisin. + +#6 +1|Hedef: +1| +1|Bir tehlike söz konusu: +1|kampı derhal dört kuleyle +1|korumalısın. + +2|Çizgili parke taşına +2|güneydoğuda kavuşacaksın. + + + + + + + + + +İpucu: + +Shift tuşu basılıyken her bir +Blupi'ye tıklarsan, birkaç +Blupi'yi aynı anda seçebilirsin. + + +@6 +1|Çözüm: +1| +1|Dört Blupi'nin hemen kaya +1|kesmesini talep etmelisin. +1|Küçük kayaları kesmek daha +1|kolay. +1| +1|Dört taş yığınını gri parke +1|taşına ulaştır ve koruma +1|kulelerini inşa etmeye başla. + +2|Virüslerin gelişini bekle ve +2|yıkımını izle. +2| +2|Diğer dört Blupi, güneydoğudaki +2|çizgili parke taşına yavaşça +2|gidebilir. + +#7 +1|Hedef: +1| +1|Dört Blupi çizgili parke +1|taşına ulaşmalı. En uzaktaki +1|Blupi ile de ilgilenmek +1|zorundasın. + + + + + +2|Dikkat et: +2| +2|Toprak, bahçe kulübesi inşa +2|etmek için uygun değil. + +@7 +1|Çözüm: +1| +1|Bir Blupi'ye domatesleri +1|kaldırmasını talep et, böylece +1|örümcekler onları yiyemeyecek. +1| +1|Diğer Blupi ile, doğudaki +1|adaya zıpla, çizgili parke +1|taşını buraya bağlayan bir +1|köprü inşa et. + +2|Domatesleri bitkin Blupi'ye +2|doğru taşı, böylece o bunları +2|yiyebilir. + +#8 +1|Hedef: +1| +1|Bir veya iki Blupi'ye mikrop +1|bulaşmasını önle ve hasta +1|olanlara bir ilaç bul. +1| +1|Son olarak, her Blupi +1|bir eve girmeli. + + + + + + + +2|İpucu: +2| +2|Bir laboratuvar kur. + +@8 +1|İpuçları: +1| +1|Laboratuvar taştan yapılmalı +1|O, sarı çiçekleri, hasta +1|Blupi'leri iyileştiren bir ilaca +1|dönüştürmende yararlı +1|olacak. + +2|Hasta Blupi'lere ilaç getirmek +2|için bir köprü inşa etmelisin. +2| +2|Evler güneydoğuda bulunmakta. + +#9 +1|Hedef: +1| +1|Buz pistini geçmek için bir +1|yol bul. +1| + + + + + + +2|Not: +2| +2|Blupi buzda yürüyebilir. Ancak +2|kaygan buzda, o bir sürü güç +2|kaybeder. + +@9 +1|İpuçları: +1| +1|Blupi'leri örümcüklerden +1|korumak için iki kule inşa +1|edilmeli. +1| +1|Yumurtaların açılması için +1|bir bahçe kulübesi ve +1|inkübatör inşa etmelisin. + +2|Buz ringini geçerken, Blupi +2|çok fazla güç kaybeder. Bu +2|yüzden geçmeden önce ona +2|domates getirmelisin. + +#10 +1|Hedef: +1| +1|Kuzeydoğudaki adaya ulaş ve +1|kazıklı çiti havaya uçur. + +2|Şimdi yapman gereken tek şey, +2|dört Blupi'yi çizgili parke +2|taşına yerleştirmek. + +@10 +1|İpuçları: +1| +1|Dört esirin doğrultusunda +1|bir köprü inşa et. Bu, +1|laboratuvar kurmak için +1|gereken kayayı kesip onu bahçe +1|kulübesinin yanına götürmene +1|olanak sağlayacak. +1| +1|Mavi çiçekler güneydoğuda. +1|Laboratuvar sayesinde, bunlar +1|dinamite dönüştürülebilir. + +2|Dinamiti kullanarak dört +2|Blupi'yi esir tutan kazıklı çiti +2|yok et. +2| +2|Öncelikle, esirleri patlamadan +2|korumak için geriye çek. + +#11 +1|Hedef: +1| +1|Kuzeydoğudaki evlere ulaş. +1|Dikkatli ol, orası sımsıkı +1|koruma altında. + +@11 +1|İpuçları: +1| +1|Kuzeybatıdaki adaya doğru bir +1|köprü inşa et ve sonra en az +1|dört paket dinamit yap. + +2|Dinamitleri kuzeye, +2|buldozerlere oldukça yakın +2|bir yere bırak. +2| +2|Dinamit yapılmadığı sürece, +2|kuzeye gitmekten kaçın. Yoksa +2|buldozerlerin ilgisini +2|çekersin. + +#12 +1|Hedef: +1| +1|Üç Blupi, yalnız bir Blupi'nin +1|bulunduğu kuzeybatıdaki bir +1|adaya varmalı. + +@12 +1|İpuçları: +1| +1|Bir bahçe kulübesi inşa et ve +1|domates yetiştir. +1| +1|Kuzeybatıda bulunan mavi +1|çiçekler ile dinamit yap. +1| + +2|Dinamiti, batıda yer alan +2|adaya ulaştır. +2| +2|Dikkatli ol, yolda iki virüs +2|gizleniyor. + +#13 +1|Hedef: +1| +1|Altı örümcekten kurtul. +1| +1|İlk dört örümcekten kurtulmak +1|kolay. Kalan ikisinden +1|kurtulmak daha zor. + + + + + + +2|İpucu: +2| +2|Laboratuvarda nasıl zehir +2|üretebileceğini öğren. + +@13 +1|İpuçları: +1| +1|İlk dört örümcek, laboratuvarda +1|yeşil çiçeklerden yapılan tuzakla +1|yakalanacak. +1| +1|Tuzaklar örümceklerin yakınına +1|yerleştirilmelidir. + +2|Son ikisi, laboratuvarda +2|değiştirilen domateslerle +2|zehirlenecek. +2| +2|Domatesleri laboratuvara +2|taşımak için bir köprü inşa et. + +#14 +1|Hedef: +1| +1|Blupi yalnızca eve gitmeli. +1| + +@14 +1|İpuçları: +1| +1|Küçük çakıl taşlarının altında +1|demir ara. Kalasları bayrağın +1|olduğu yere bırak ve maden +1|inşa et. +1| +1|Atölye inşa etmek için kaya kes, +1|böylece demiri kullanabilirsin. + +2|Bir bomba al, jipe bin ve +2|doğuya git. Jip seni +2|buldozerlerden koruyacak. +2| +2|Kazıklı çite vardığında, jipi +2|derhal terketmelisin, saatli +2|bombayı bırakmalısın ve +2|çalıştırmalısın. Daha sonra jipe +2|geri binmelisin ve oradan +2|uzaklaşmalısın. + +#15 +1|Hedef: +1| +1|Yalnız bir Blupi kuzeydoğudaki +1|eve ulaşmalı. + +2|Bunu yapmak için, birçok +2|düşman tesisini yok etmelisin. + +@15 +1|İpuçları: +1| +1|Çizgili parke taşının olduğu +1|yere bir bahçe kulübesi ve +1|iki koruma kulesi inşa et. +1| +1|Doğudaki adayı birleştirmek +1|için bir köprü inşa et. +1|Çeşitli çiçekler topla ve +1|bunları ana kampa geri getir. + +2|Bir laboratuvar inşa et, +2|dinamit ve yapışkan tuzaklar +2|yap. Kampı içeriden yapışkan +2|tuzaklar ile, dışarıdan +2|dinamitler ile koru. +2| +2|Yeterli dinamitin ve tuzağın +2|olduğunu düşündüğünde, düşman +2|kampını yok etmek için +2|kuzeydoğuya ufak bir komando +2|birliği gönder. + +#16 +1|Durum: +1| +1|Blupi, gezegeninin ağaç olmayan, +1|kurak bir yerinde kayıp. + + + + +2|Hedef: +2| +2|İki Blupi kendi köylerine geri +2|dönmeli. + +@16 +1|İpuçları: +1| +1|Kuzeydoğudaki madeni bul, bir +1|atölye inşa etmek için kaya kes, +1|saatli bir bomba ve iki jip yap ve +1|güneybatıdaki düşman kampını +1|ara. + +2|Düşman kampını koruyan bariyeri +2|patlat. Buldozeri de patlatmaya +2|çalış. +2| +2|Güneye git, yalnız duran bir +2|ağacı ara ve ışınlayıcı inşa et. + +#17 +1|Hedef: +1| +1|Beş Blupi bir eve ulaşmalı. +1| + +2|Dikkat, bir ev düşman kampının +2|arkasında. + + + + + + + + + + + + +İpucu: + +Shift tuşu basılıyken her bir +Blupi'ye tıklarsan, birkaç +Blupi'yi aynı anda seçebilirsin. + +@17 +1|İpuçları: +1| +1|Bir Blupi şimdi adanın +1|batısındaki eve gidebilir. +1|Diğer dördü buldozerlerden +1|dolayı derhal oradan ayrılmalı. +1|Blupi'ler kuzeydoğuya gitmeli. + +2|Kuzeydoğunun daha ötesinde, +2|kazıklı çitle sarılı bir köy +2|bulacaksın. +2| +2|Köyün kuzeyinde bir sürü demir +2|var. +2| +2|Bir kayık yap ve saatli bir +2|bomba ile kuzeydoğuya git. + +#18 +1|Durum: +1| +1|Blupi çiçek toplarken, evinden +1|çok uzakta olduğunu farketmedi. +1|O şimdi düşmanlarla dolu bir +1|alanda kayboldu. + + + + + +2|Hedef: +2| +2|Blupi kaçmalı ve eve dönmenin +2|bir yolunu bulmalı. + +@18 +1|İpuçları: +1| +1|Batıya uzanan nehri bul ve bir +1|kayık yap. Dikkatli ol, bir +1|sürü virüs etrafta geziyor. + +2|Kayıkla, duvarı geçebilir ve +2|nehir kıyısına çıkabilirsin. +2| +2|Ev şimdi çok uzak değil. +2|Buldozerlerden uzak durma +2|konusunda dikkatli ol. + +#19 +1|Durum: +1| +1|Dört buldozer, Blupi'lerin +1|evini tehlike altına sokuyor. + + + + + +2|Hedef: +2| +2|Buldozerleri yok et. + +@19 +1|İpuçları: +1| +1|Bir Blupi'nin demir aramasını +1|ve zırh yapmasını talep et. +1|Zırh, onu yangından koruyacak. +1| +1|Doğuya git ve bir kayık yap. +1|Karaya çık ve ağaç olan bir +1|ada ara. Ağacı kes ve +1|tahtayı daha büyük olan bir +2|adaya götür. Bir ışınlayıcı +2|inşa et. O seni silah +2|deposuna götürecek. +2| +2|Etrafı çevreleyen duvarların +2|yanına birkaç dinamit koy ve +2|onları patlat. Kalan dinamitle, +2|buldozerleri yok edebilirsin. + +#20 +1|Hedef: +1| +1|Bütün düşman tesislerini yok +1|et. +1| + +@20 +1|İpuçları: +1| +1|Düşman kampını koruyan +1|bariyerleri yok etmeden önce, +1|olabildiğnce çok dinamit, +1|tuzak, vb. üret. + +#21 +1|Durum: +1| +1|Blupi, kötü bir robot +1|tarafından ele geçirildi. +1|O, robotun kampında esir +1|olarak tutuluyor. + + + + +2|Hedef: +2| +2|Blupi kaçmalı ve evini +2|bulmalı. + +@21 +1|İpuçları: +1| +1|Kuzeydoğuda bulunan dinamiti +1|al. Onu, kayalardaki bir +1|boşluğa bakan mavi bir +1|bariyerin yanına yerleştir. +1|Buldozer gelecek ve dinamitin +1|patlamasına neden olacak. Bu +1|da bariyeri patlatacak. + +2|Nehre ulaşana kadar doğuya +2|doğru koş. Kalaslarla bir +2|kayık yap. İkinci kalas +2|yığınına, sonra yine bir kayık +2|yapmak için ihtiyacın olacak. +2|Bunu yapmadan önce, +2|elekrikçarparı yapışkan bir +2|tuzakla yakalamalısın ve +2|doğudaki mavi bariyeri saatli +2|bir bombayla yok etmelisin. + +#22 +1|Hedefler: +1| +1|1) Kayıklar yap. +1| +1|2) Bütün adaları keşfet. +1| +1|3) Bütün düşman tesislerini +1| yok et + +@22 +1|İpuçları: +1| +1|Kuzeydoğudaki ada bir sürü +1|demire sahip. + +2|Doğudaki ada, dinamit ve +2|yapışkan tuzak yapmak için +2|gereken her şeye sahip. + +#23 +1|Durum: +1| +1|Blupi çok meraklı: Robotu iyice +1|gözlemledikten sonra, şimdi +1|robotun kendini kaybettiğini +1|farketti. + + + + + +2|Hedef: +2| +2|Destek getir ve düşmanı yok +2|et. + + +@23 +1|İpuçları: +1| +1|Ayrı olan Blupi, robottan +1|uzaklaşmalı ve batıya gitmeli. +1|Blupi tahtaya ulaşmak için +1|kaya kesmeli ve ışınlayıcı +1|inşa etmeli. + +2|İkinci Blupi grubuyla, +2|bir kayık yapmalısın, +2|kuzeydoğudaki bombayı +2|bulmalısın ve güneydeki +2|bariyeri patlatmalısın. Bu, +2|terkedilecek olan adaya tahta +2|getirmeni sağlayacak, böylece +2|kaybolmuş Blupi'ye katılmak +2|ve yardım etmek için bir +2|ışınlayıcı inşa edebilirsin. + +#24 +1|Durum: +1| +1|Bölge düşmanlarla dolu. +1| + + + +2|Hedef: +2| +2|Bütün düşmanları yok et. + +@24 +1|İpuçları: +1| +1|Yangından uzak durmak için +1|güneydoğuya git ve kalan +1|ağaçla bir kayık yap. +1| +1|Kampta biraz demir bulacaksın. +1| + +2|Kampın kuzeyinde biraz yumurta +2|bulacaksın. + +#25 +1|Blupi robotun kendi gezegeninden +1|garip bir şey getirdiğinden +1|şüpheleniyor: +1| +1| Platin.... +1| +1|Robotun roketinin yanında +2|duran platin, Blupi'nin düşman +2|teknolojisine erişimini +2|sağlayacak. +2| + + +2|Hedef: +2|Bir küp platini çizgili parke +2|taşının üzerine koy. + +@25 +1|İpuçları: +1| +1|İki buldozeri yapışkan tuzaklar +1|ile imha et. İlk düşman kampının +1|kuzeyinde bir kayık yap, sonra +1|saatli bir bomba ile karaya çık +1|ve doğuya git. +1| +1|Kayaların arasında, güneye doğru +1|giden bir patika ara. Roketin +2|bulunduğu düşman kampı doğuda +2|uzakta bir yerde. Platini ele +2|geçirebilmek için bariyeri +2|patlatman gerekecek. +2| +2|Platini ana kampa geri götür. + +#26 +1|Platin küp, senin düşman +1|teknolojisine erişimini +1|sağlayacak, o yüzden onu +1|doğru şekilde kullan. + + + + + +2|Hedef: +2| +2|Blupi'nin evini bulmasına +2|yardım et. + +@26 +1|İpuçları: +1| +1|Atölyede platin küpü kullanarak +1|yardımcı bir robot yap ve saatli +1|bir bomba yap. +1| +1|Robotu ve bombayı al. Robot, +1|batıdaki düşman kampını +1|farkedilmeden geçebilir. +2|Kuzeydeki bariyeri patlat ve +2|ana kamptaki Blupi'leri beslemek +2|için domates al. +2| +2|İlk zıplayıştan önce domatesleri +2|yere bırak. + +#27 +1|Durum: +1| +1|Robot, Blupi köyünün yakınına +1|kendi köyünü kurma +1|küstahlığında bulundu. + + + + +2|Hedef: +2| +2|Düşman kampına ulaş ve +2|her şeyi yok et. + +@27 +1|İpuçları: +1| +1|Hemen bir ışınlayıcı inşa et, +1|böylece yumurtalı adaya +1|ulaşabilirsin. Taş yığınlarının +1|olduğu yere iki koruma kulesi inşa +1|et. Her kulenin sağına ve soluna +1|kazıklı çit kur. + +2|Şimdi nefes alabilirsin ! +2| +2|Kuzeyde bulunan düşman +2|kampına ulaşmak için iki yolun +2|var, ya kayıkla ya da köprü +2|yaparak. +2| +2|Seçmek sana düşüyor ! + +#28 +1|Durum: +1| +1|Blupi, evini inşa ederken bir +1|hata yaptı: etrafına bir duvar +1|ördü. + + + + + +2|Hedef: +2| +2|Blupi yalnızca eve gitmeli. + +@28 +1|İpuçları: +1| +1|Kuzeyde küçük bir adada bir +1|sürü yumurta var. +1| +1|Kuzeyden ve güneyden gelen +1|buldozerleri önlemek için +1|düşman kampını çabucak geçmek +1|zorundasın, böylece mavi +1|çiçekleri toplayabilirsin. Bir başka +2|Blupi bunları dinamit yapmak +2|için götürebilir. +2| +2|Kullanılabilecek tek kaya, düşman +2|kampının güneyinde, koruma +2|kulesinin hemen dışında +2|bulunuyor. + +#29 +1|Durum: +1| +1|Boş alanlar, robot ve destekçileri +1|tarafından git gide dolduruluyor. + + + + + +2|Hedef: +2| +2|Blupi köyünü kurmalı ve iyi +2|savunma taktikleri geliştirmeli. +2| +2|Sonra o, bütün düşmanlara +2|saldırıp onları yok edebilir. + +@29 +1|İpuçları: +1| +1|Blupi; kuzeybatı, kuzeydoğu ve +1|güneydoğu taraflarında koruma +1|kuleleri inşa etmeli. Bütün kayalar +1|kuzeybatıda bulunmakta. +1| +1|Kazıklı çit yakınındaki ağaçları +1|sakın kesme. Onlar, zıplayan +1|bombalara karşı faydalı olabilir. + +2|Doğuda bulunan yeşil çiçekler, +2|köyü savunmak amacıyla +2|yapışkan tuzaklar yapmanı +2|sağlayacak. +2| +2|Güneybatıda demir çıkar ve +2|bombalar ve zırhlar yap. + +#30 +1|Durum: +1| +1|Bu savaş daha fazla süremez. +1|Blupi ve son robot bir +1|anlaşmaya vardılar: Robotun, +1|Blupi'nin gezegeninden ayrılması +1|karşılığında, Blupi, robotun +1|roketine dönmesine yardım +1|edecek. + + + + +2|Hedef: +2| +2|Rokete giden patikayı hazırla, +2|böylece robot, gezegenden +2|ayrılabilir. Savaşı kaybetmekten +2|dolayı robot kızgın, bu yüzden +2|patika bitene kadar kımıldamayı +2|reddediyor. + +@30 +1|İpuçları: +1| +1|Güneydoğuda bir kaya kes. Bir +1|ağaç kes ve bir kayık yap. +1|Kayıkla, kuzeydoğuda bir ada +1|ara. Biraz demir ara, bir maden +1|ve atölye kur. Robotun +1|etrafındaki bariyerleri patlatmanı +2|sağlayacak olan bir bomba yap. +2| +2|Yapman gereken son şey bir +2|köprü yapmak, böylece robot, +2|roketine geri dönebilir. \ No newline at end of file diff --git a/resources/data/user000.blp b/resources/data/user000.blp new file mode 100644 index 0000000..84700cf Binary files /dev/null and b/resources/data/user000.blp differ diff --git a/resources/data/user001.blp b/resources/data/user001.blp new file mode 100644 index 0000000..bc362f3 Binary files /dev/null and b/resources/data/user001.blp differ diff --git a/resources/data/user002.blp b/resources/data/user002.blp new file mode 100644 index 0000000..d22ccc0 Binary files /dev/null and b/resources/data/user002.blp differ diff --git a/resources/data/user003.blp b/resources/data/user003.blp new file mode 100644 index 0000000..677d442 Binary files /dev/null and b/resources/data/user003.blp differ diff --git a/resources/data/user004.blp b/resources/data/user004.blp new file mode 100644 index 0000000..0b723ca Binary files /dev/null and b/resources/data/user004.blp differ diff --git a/resources/data/user005.blp b/resources/data/user005.blp new file mode 100644 index 0000000..82fa79e Binary files /dev/null and b/resources/data/user005.blp differ diff --git a/resources/data/user006.blp b/resources/data/user006.blp new file mode 100644 index 0000000..a3a261c Binary files /dev/null and b/resources/data/user006.blp differ diff --git a/resources/data/user007.blp b/resources/data/user007.blp new file mode 100644 index 0000000..1694fdf Binary files /dev/null and b/resources/data/user007.blp differ diff --git a/resources/data/user008.blp b/resources/data/user008.blp new file mode 100644 index 0000000..aaa62c6 Binary files /dev/null and b/resources/data/user008.blp differ diff --git a/resources/data/user009.blp b/resources/data/user009.blp new file mode 100644 index 0000000..a262991 Binary files /dev/null and b/resources/data/user009.blp differ diff --git a/resources/data/world000.blp b/resources/data/world000.blp new file mode 100644 index 0000000..16ad212 Binary files /dev/null and b/resources/data/world000.blp differ diff --git a/resources/data/world001.blp b/resources/data/world001.blp new file mode 100644 index 0000000..236cafa Binary files /dev/null and b/resources/data/world001.blp differ diff --git a/resources/data/world002.blp b/resources/data/world002.blp new file mode 100644 index 0000000..5215115 Binary files /dev/null and b/resources/data/world002.blp differ diff --git a/resources/data/world003.blp b/resources/data/world003.blp new file mode 100644 index 0000000..83128b4 Binary files /dev/null and b/resources/data/world003.blp differ diff --git a/resources/data/world004.blp b/resources/data/world004.blp new file mode 100644 index 0000000..5d57ee7 Binary files /dev/null and b/resources/data/world004.blp differ diff --git a/resources/data/world005.blp b/resources/data/world005.blp new file mode 100644 index 0000000..ff559c1 Binary files /dev/null and b/resources/data/world005.blp differ diff --git a/resources/data/world100.blp b/resources/data/world100.blp new file mode 100644 index 0000000..92fd05e Binary files /dev/null and b/resources/data/world100.blp differ diff --git a/resources/data/world101.blp b/resources/data/world101.blp new file mode 100644 index 0000000..5479c82 Binary files /dev/null and b/resources/data/world101.blp differ diff --git a/resources/data/world102.blp b/resources/data/world102.blp new file mode 100644 index 0000000..41f99c8 Binary files /dev/null and b/resources/data/world102.blp differ diff --git a/resources/data/world103.blp b/resources/data/world103.blp new file mode 100644 index 0000000..81e6a04 Binary files /dev/null and b/resources/data/world103.blp differ diff --git a/resources/data/world104.blp b/resources/data/world104.blp new file mode 100644 index 0000000..f34cc4f Binary files /dev/null and b/resources/data/world104.blp differ diff --git a/resources/data/world105.blp b/resources/data/world105.blp new file mode 100644 index 0000000..6bf7cba Binary files /dev/null and b/resources/data/world105.blp differ diff --git a/resources/data/world106.blp b/resources/data/world106.blp new file mode 100644 index 0000000..3153ec4 Binary files /dev/null and b/resources/data/world106.blp differ diff --git a/resources/data/world107.blp b/resources/data/world107.blp new file mode 100644 index 0000000..51ebb04 Binary files /dev/null and b/resources/data/world107.blp differ diff --git a/resources/data/world108.blp b/resources/data/world108.blp new file mode 100644 index 0000000..a5f1f5e Binary files /dev/null and b/resources/data/world108.blp differ diff --git a/resources/data/world109.blp b/resources/data/world109.blp new file mode 100644 index 0000000..28c7942 Binary files /dev/null and b/resources/data/world109.blp differ diff --git a/resources/data/world110.blp b/resources/data/world110.blp new file mode 100644 index 0000000..80fca4a Binary files /dev/null and b/resources/data/world110.blp differ diff --git a/resources/data/world111.blp b/resources/data/world111.blp new file mode 100644 index 0000000..ab31171 Binary files /dev/null and b/resources/data/world111.blp differ diff --git a/resources/data/world112.blp b/resources/data/world112.blp new file mode 100644 index 0000000..e257f54 Binary files /dev/null and b/resources/data/world112.blp differ diff --git a/resources/data/world113.blp b/resources/data/world113.blp new file mode 100644 index 0000000..73933d5 Binary files /dev/null and b/resources/data/world113.blp differ diff --git a/resources/data/world114.blp b/resources/data/world114.blp new file mode 100644 index 0000000..ec709ce Binary files /dev/null and b/resources/data/world114.blp differ diff --git a/resources/data/world115.blp b/resources/data/world115.blp new file mode 100644 index 0000000..5bbce7d Binary files /dev/null and b/resources/data/world115.blp differ diff --git a/resources/data/world116.blp b/resources/data/world116.blp new file mode 100644 index 0000000..4f77aa2 Binary files /dev/null and b/resources/data/world116.blp differ diff --git a/resources/data/world117.blp b/resources/data/world117.blp new file mode 100644 index 0000000..64a6d17 Binary files /dev/null and b/resources/data/world117.blp differ diff --git a/resources/data/world118.blp b/resources/data/world118.blp new file mode 100644 index 0000000..0cac99d Binary files /dev/null and b/resources/data/world118.blp differ diff --git a/resources/data/world119.blp b/resources/data/world119.blp new file mode 100644 index 0000000..d63aff5 Binary files /dev/null and b/resources/data/world119.blp differ diff --git a/resources/data/world120.blp b/resources/data/world120.blp new file mode 100644 index 0000000..a917b8a Binary files /dev/null and b/resources/data/world120.blp differ diff --git a/resources/data/world121.blp b/resources/data/world121.blp new file mode 100644 index 0000000..7f83eff Binary files /dev/null and b/resources/data/world121.blp differ diff --git a/resources/data/world122.blp b/resources/data/world122.blp new file mode 100644 index 0000000..36e65e4 Binary files /dev/null and b/resources/data/world122.blp differ diff --git a/resources/data/world123.blp b/resources/data/world123.blp new file mode 100644 index 0000000..8478c03 Binary files /dev/null and b/resources/data/world123.blp differ diff --git a/resources/data/world124.blp b/resources/data/world124.blp new file mode 100644 index 0000000..345b877 Binary files /dev/null and b/resources/data/world124.blp differ diff --git a/resources/data/world125.blp b/resources/data/world125.blp new file mode 100644 index 0000000..084dac3 Binary files /dev/null and b/resources/data/world125.blp differ diff --git a/resources/data/world126.blp b/resources/data/world126.blp new file mode 100644 index 0000000..3d135ac Binary files /dev/null and b/resources/data/world126.blp differ diff --git a/resources/data/world127.blp b/resources/data/world127.blp new file mode 100644 index 0000000..63ac340 Binary files /dev/null and b/resources/data/world127.blp differ diff --git a/resources/data/world128.blp b/resources/data/world128.blp new file mode 100644 index 0000000..5a577e6 Binary files /dev/null and b/resources/data/world128.blp differ diff --git a/resources/data/world129.blp b/resources/data/world129.blp new file mode 100644 index 0000000..0bbe7e6 Binary files /dev/null and b/resources/data/world129.blp differ diff --git a/resources/data/world130.dev.blp b/resources/data/world130.dev.blp new file mode 100644 index 0000000..1c4fb08 Binary files /dev/null and b/resources/data/world130.dev.blp differ diff --git a/resources/data/world131.dev.blp b/resources/data/world131.dev.blp new file mode 100644 index 0000000..41b10d0 Binary files /dev/null and b/resources/data/world131.dev.blp differ diff --git a/resources/data/world132.dev.blp b/resources/data/world132.dev.blp new file mode 100644 index 0000000..bc51d2d Binary files /dev/null and b/resources/data/world132.dev.blp differ diff --git a/resources/data/world133.dev.blp b/resources/data/world133.dev.blp new file mode 100644 index 0000000..f591af6 Binary files /dev/null and b/resources/data/world133.dev.blp differ diff --git a/resources/data/world134.dev.blp b/resources/data/world134.dev.blp new file mode 100644 index 0000000..130f3e5 Binary files /dev/null and b/resources/data/world134.dev.blp differ diff --git a/resources/data/world135.dev.blp b/resources/data/world135.dev.blp new file mode 100644 index 0000000..832c8c7 Binary files /dev/null and b/resources/data/world135.dev.blp differ diff --git a/resources/data/world136.dev.blp b/resources/data/world136.dev.blp new file mode 100644 index 0000000..17cafc5 Binary files /dev/null and b/resources/data/world136.dev.blp differ diff --git a/resources/data/world137.dev.blp b/resources/data/world137.dev.blp new file mode 100644 index 0000000..b568e79 Binary files /dev/null and b/resources/data/world137.dev.blp differ diff --git a/resources/data/world139.dev.blp b/resources/data/world139.dev.blp new file mode 100644 index 0000000..7017048 Binary files /dev/null and b/resources/data/world139.dev.blp differ diff --git a/resources/data/world140.dev.blp b/resources/data/world140.dev.blp new file mode 100644 index 0000000..11be40b Binary files /dev/null and b/resources/data/world140.dev.blp differ diff --git a/resources/data/world141.dev.blp b/resources/data/world141.dev.blp new file mode 100644 index 0000000..b36c71b Binary files /dev/null and b/resources/data/world141.dev.blp differ diff --git a/resources/data/world142.dev.blp b/resources/data/world142.dev.blp new file mode 100644 index 0000000..2a8cbdb Binary files /dev/null and b/resources/data/world142.dev.blp differ diff --git a/resources/data/world148.dev.blp b/resources/data/world148.dev.blp new file mode 100644 index 0000000..b8cc50a Binary files /dev/null and b/resources/data/world148.dev.blp differ diff --git a/resources/data/world150.blp b/resources/data/world150.blp new file mode 100644 index 0000000..98a9d66 Binary files /dev/null and b/resources/data/world150.blp differ diff --git a/resources/data/world151.blp b/resources/data/world151.blp new file mode 100644 index 0000000..ea63e27 Binary files /dev/null and b/resources/data/world151.blp differ diff --git a/resources/data/world152.blp b/resources/data/world152.blp new file mode 100644 index 0000000..daa9886 Binary files /dev/null and b/resources/data/world152.blp differ diff --git a/resources/data/world153.blp b/resources/data/world153.blp new file mode 100644 index 0000000..53a8526 Binary files /dev/null and b/resources/data/world153.blp differ diff --git a/resources/data/world200.blp b/resources/data/world200.blp new file mode 100755 index 0000000..2ea8f49 Binary files /dev/null and b/resources/data/world200.blp differ diff --git a/resources/data/world201.blp b/resources/data/world201.blp new file mode 100644 index 0000000..856d158 Binary files /dev/null and b/resources/data/world201.blp differ diff --git a/resources/data/world202.blp b/resources/data/world202.blp new file mode 100644 index 0000000..d7b59f9 Binary files /dev/null and b/resources/data/world202.blp differ diff --git a/resources/data/world203.blp b/resources/data/world203.blp new file mode 100644 index 0000000..7eef8fc Binary files /dev/null and b/resources/data/world203.blp differ diff --git a/resources/data/world204.blp b/resources/data/world204.blp new file mode 100644 index 0000000..68c91ca Binary files /dev/null and b/resources/data/world204.blp differ diff --git a/resources/data/world205.blp b/resources/data/world205.blp new file mode 100644 index 0000000..6fb0ff5 Binary files /dev/null and b/resources/data/world205.blp differ diff --git a/resources/data/world206.blp b/resources/data/world206.blp new file mode 100644 index 0000000..5a95171 Binary files /dev/null and b/resources/data/world206.blp differ diff --git a/resources/data/world207.blp b/resources/data/world207.blp new file mode 100644 index 0000000..1d57ccf Binary files /dev/null and b/resources/data/world207.blp differ diff --git a/resources/data/world208.blp b/resources/data/world208.blp new file mode 100644 index 0000000..53d7c9e Binary files /dev/null and b/resources/data/world208.blp differ diff --git a/resources/data/world209.blp b/resources/data/world209.blp new file mode 100644 index 0000000..5e43be6 Binary files /dev/null and b/resources/data/world209.blp differ diff --git a/resources/data/world210.blp b/resources/data/world210.blp new file mode 100644 index 0000000..9645a0c Binary files /dev/null and b/resources/data/world210.blp differ diff --git a/resources/data/world211.blp b/resources/data/world211.blp new file mode 100644 index 0000000..71aa31e Binary files /dev/null and b/resources/data/world211.blp differ diff --git a/resources/data/world212.blp b/resources/data/world212.blp new file mode 100644 index 0000000..9f28e4e Binary files /dev/null and b/resources/data/world212.blp differ diff --git a/resources/data/world213.blp b/resources/data/world213.blp new file mode 100644 index 0000000..e45b8dc Binary files /dev/null and b/resources/data/world213.blp differ diff --git a/resources/data/world214.blp b/resources/data/world214.blp new file mode 100644 index 0000000..c8fcef9 Binary files /dev/null and b/resources/data/world214.blp differ diff --git a/resources/data/world215.blp b/resources/data/world215.blp new file mode 100644 index 0000000..a884fa8 Binary files /dev/null and b/resources/data/world215.blp differ diff --git a/resources/icon/blupi.icns b/resources/icon/blupi.icns new file mode 100644 index 0000000..ccf2c7b Binary files /dev/null and b/resources/icon/blupi.icns differ diff --git a/resources/icon/blupi.ico b/resources/icon/blupi.ico new file mode 100644 index 0000000..b03c465 Binary files /dev/null and b/resources/icon/blupi.ico differ diff --git a/resources/icon/blupi.iconset/icon_128x128.png b/resources/icon/blupi.iconset/icon_128x128.png new file mode 100644 index 0000000..26f623c Binary files /dev/null and b/resources/icon/blupi.iconset/icon_128x128.png differ diff --git a/resources/icon/blupi.iconset/icon_128x128@2x.png b/resources/icon/blupi.iconset/icon_128x128@2x.png new file mode 100644 index 0000000..576de52 Binary files /dev/null and b/resources/icon/blupi.iconset/icon_128x128@2x.png differ diff --git a/resources/icon/blupi.iconset/icon_16x16.png b/resources/icon/blupi.iconset/icon_16x16.png new file mode 100644 index 0000000..46a8e70 Binary files /dev/null and b/resources/icon/blupi.iconset/icon_16x16.png differ diff --git a/resources/icon/blupi.iconset/icon_16x16@2x.png b/resources/icon/blupi.iconset/icon_16x16@2x.png new file mode 100644 index 0000000..317bbb9 Binary files /dev/null and b/resources/icon/blupi.iconset/icon_16x16@2x.png differ diff --git a/resources/icon/blupi.iconset/icon_256x256.png b/resources/icon/blupi.iconset/icon_256x256.png new file mode 100644 index 0000000..4635c5d Binary files /dev/null and b/resources/icon/blupi.iconset/icon_256x256.png differ diff --git a/resources/icon/blupi.iconset/icon_256x256@2x.png b/resources/icon/blupi.iconset/icon_256x256@2x.png new file mode 100644 index 0000000..3b4ed88 Binary files /dev/null and b/resources/icon/blupi.iconset/icon_256x256@2x.png differ diff --git a/resources/icon/blupi.iconset/icon_32x32.png b/resources/icon/blupi.iconset/icon_32x32.png new file mode 100644 index 0000000..a80dd22 Binary files /dev/null and b/resources/icon/blupi.iconset/icon_32x32.png differ diff --git a/resources/icon/blupi.iconset/icon_32x32@2x.png b/resources/icon/blupi.iconset/icon_32x32@2x.png new file mode 100644 index 0000000..2b7e26b Binary files /dev/null and b/resources/icon/blupi.iconset/icon_32x32@2x.png differ diff --git a/resources/icon/blupi.iconset/icon_512x512.png b/resources/icon/blupi.iconset/icon_512x512.png new file mode 100644 index 0000000..e29fefe Binary files /dev/null and b/resources/icon/blupi.iconset/icon_512x512.png differ diff --git a/resources/icon/blupi.iconset/icon_512x512@2x.png b/resources/icon/blupi.iconset/icon_512x512@2x.png new file mode 100644 index 0000000..bf4f9ec Binary files /dev/null and b/resources/icon/blupi.iconset/icon_512x512@2x.png differ diff --git a/resources/icon/hicolor/128x128/apps/blupi.png b/resources/icon/hicolor/128x128/apps/blupi.png new file mode 100644 index 0000000..26f623c Binary files /dev/null and b/resources/icon/hicolor/128x128/apps/blupi.png differ diff --git a/resources/icon/hicolor/16x16/apps/blupi.png b/resources/icon/hicolor/16x16/apps/blupi.png new file mode 100644 index 0000000..46a8e70 Binary files /dev/null and b/resources/icon/hicolor/16x16/apps/blupi.png differ diff --git a/resources/icon/hicolor/256x256/apps/blupi.png b/resources/icon/hicolor/256x256/apps/blupi.png new file mode 100644 index 0000000..4635c5d Binary files /dev/null and b/resources/icon/hicolor/256x256/apps/blupi.png differ diff --git a/resources/icon/hicolor/32x32/apps/blupi.png b/resources/icon/hicolor/32x32/apps/blupi.png new file mode 100644 index 0000000..a80dd22 Binary files /dev/null and b/resources/icon/hicolor/32x32/apps/blupi.png differ diff --git a/resources/icon/hicolor/48x48/apps/blupi.png b/resources/icon/hicolor/48x48/apps/blupi.png new file mode 100644 index 0000000..e7b91b8 Binary files /dev/null and b/resources/icon/hicolor/48x48/apps/blupi.png differ diff --git a/resources/icon/hicolor/512x512/apps/blupi.png b/resources/icon/hicolor/512x512/apps/blupi.png new file mode 100644 index 0000000..e29fefe Binary files /dev/null and b/resources/icon/hicolor/512x512/apps/blupi.png differ diff --git a/resources/icon/hicolor/64x64/apps/blupi.png b/resources/icon/hicolor/64x64/apps/blupi.png new file mode 100644 index 0000000..a6f2732 Binary files /dev/null and b/resources/icon/hicolor/64x64/apps/blupi.png differ diff --git a/resources/icon/hicolor/scalable/apps/blupi.svg b/resources/icon/hicolor/scalable/apps/blupi.svg new file mode 100644 index 0000000..e49a2ac --- /dev/null +++ b/resources/icon/hicolor/scalable/apps/blupi.svg @@ -0,0 +1,1399 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/image/back-book.png b/resources/image/back-book.png new file mode 100644 index 0000000..9a3814f Binary files /dev/null and b/resources/image/back-book.png differ diff --git a/resources/image/back-build.png b/resources/image/back-build.png new file mode 100644 index 0000000..d1c0069 Binary files /dev/null and b/resources/image/back-build.png differ diff --git a/resources/image/back-bye.png b/resources/image/back-bye.png new file mode 100644 index 0000000..dd2041c Binary files /dev/null and b/resources/image/back-bye.png differ diff --git a/resources/image/back-chest-r.png b/resources/image/back-chest-r.png new file mode 100644 index 0000000..08cc225 Binary files /dev/null and b/resources/image/back-chest-r.png differ diff --git a/resources/image/back-chest-w.png b/resources/image/back-chest-w.png new file mode 100644 index 0000000..90aad28 Binary files /dev/null and b/resources/image/back-chest-w.png differ diff --git a/resources/image/back-disco.png b/resources/image/back-disco.png new file mode 100644 index 0000000..4bae9fd Binary files /dev/null and b/resources/image/back-disco.png differ diff --git a/resources/image/back-lost.png b/resources/image/back-lost.png new file mode 100644 index 0000000..6625928 Binary files /dev/null and b/resources/image/back-lost.png differ diff --git a/resources/image/back-setup.png b/resources/image/back-setup.png new file mode 100644 index 0000000..1b6f116 Binary files /dev/null and b/resources/image/back-setup.png differ diff --git a/resources/image/back-stars.png b/resources/image/back-stars.png new file mode 100644 index 0000000..759a27f Binary files /dev/null and b/resources/image/back-stars.png differ diff --git a/resources/image/back-win.png b/resources/image/back-win.png new file mode 100644 index 0000000..000b611 Binary files /dev/null and b/resources/image/back-win.png differ diff --git a/resources/image/bignum.png b/resources/image/bignum.png new file mode 100644 index 0000000..22679bf Binary files /dev/null and b/resources/image/bignum.png differ diff --git a/resources/image/blupi.png b/resources/image/blupi.png new file mode 100644 index 0000000..57b9898 Binary files /dev/null and b/resources/image/blupi.png differ diff --git a/resources/image/build.png b/resources/image/build.png new file mode 100644 index 0000000..875cc1c Binary files /dev/null and b/resources/image/build.png differ diff --git a/resources/image/button.png b/resources/image/button.png new file mode 100644 index 0000000..93ef095 Binary files /dev/null and b/resources/image/button.png differ diff --git a/resources/image/button00.png b/resources/image/button00.png new file mode 100644 index 0000000..7458180 Binary files /dev/null and b/resources/image/button00.png differ diff --git a/resources/image/bye.png b/resources/image/bye.png new file mode 100644 index 0000000..1769566 Binary files /dev/null and b/resources/image/bye.png differ diff --git a/resources/image/floor000.png b/resources/image/floor000.png new file mode 100644 index 0000000..233811e Binary files /dev/null and b/resources/image/floor000.png differ diff --git a/resources/image/floor001.png b/resources/image/floor001.png new file mode 100644 index 0000000..bfb2501 Binary files /dev/null and b/resources/image/floor001.png differ diff --git a/resources/image/floor002.png b/resources/image/floor002.png new file mode 100644 index 0000000..7a6b5e8 Binary files /dev/null and b/resources/image/floor002.png differ diff --git a/resources/image/floor003.png b/resources/image/floor003.png new file mode 100644 index 0000000..925c46d Binary files /dev/null and b/resources/image/floor003.png differ diff --git a/resources/image/fog.png b/resources/image/fog.png new file mode 100644 index 0000000..033447f Binary files /dev/null and b/resources/image/fog.png differ diff --git a/resources/image/he/init.png b/resources/image/he/init.png new file mode 100644 index 0000000..9780325 Binary files /dev/null and b/resources/image/he/init.png differ diff --git a/resources/image/help.png b/resources/image/help.png new file mode 100644 index 0000000..8b03872 Binary files /dev/null and b/resources/image/help.png differ diff --git a/resources/image/hili.png b/resources/image/hili.png new file mode 100644 index 0000000..da372d5 Binary files /dev/null and b/resources/image/hili.png differ diff --git a/resources/image/history0.png b/resources/image/history0.png new file mode 100644 index 0000000..6f2921a Binary files /dev/null and b/resources/image/history0.png differ diff --git a/resources/image/history1.png b/resources/image/history1.png new file mode 100644 index 0000000..61bb284 Binary files /dev/null and b/resources/image/history1.png differ diff --git a/resources/image/info000.png b/resources/image/info000.png new file mode 100644 index 0000000..7143d40 Binary files /dev/null and b/resources/image/info000.png differ diff --git a/resources/image/info001.png b/resources/image/info001.png new file mode 100644 index 0000000..e94f16f Binary files /dev/null and b/resources/image/info001.png differ diff --git a/resources/image/info002.png b/resources/image/info002.png new file mode 100644 index 0000000..6a46f8e Binary files /dev/null and b/resources/image/info002.png differ diff --git a/resources/image/init.png b/resources/image/init.png new file mode 100644 index 0000000..cfbfd6d Binary files /dev/null and b/resources/image/init.png differ diff --git a/resources/image/insert.png b/resources/image/insert.png new file mode 100644 index 0000000..f48df1e Binary files /dev/null and b/resources/image/insert.png differ diff --git a/resources/image/intro1.png b/resources/image/intro1.png new file mode 100644 index 0000000..45d2c32 Binary files /dev/null and b/resources/image/intro1.png differ diff --git a/resources/image/jauge.png b/resources/image/jauge.png new file mode 100644 index 0000000..f19d06c Binary files /dev/null and b/resources/image/jauge.png differ diff --git a/resources/image/last000.png b/resources/image/last000.png new file mode 100644 index 0000000..d980b86 Binary files /dev/null and b/resources/image/last000.png differ diff --git a/resources/image/last001.png b/resources/image/last001.png new file mode 100644 index 0000000..4dfdae3 Binary files /dev/null and b/resources/image/last001.png differ diff --git a/resources/image/last002.png b/resources/image/last002.png new file mode 100644 index 0000000..d201079 Binary files /dev/null and b/resources/image/last002.png differ diff --git a/resources/image/little.png b/resources/image/little.png new file mode 100644 index 0000000..d6ec018 Binary files /dev/null and b/resources/image/little.png differ diff --git a/resources/image/lost.png b/resources/image/lost.png new file mode 100644 index 0000000..8add78e Binary files /dev/null and b/resources/image/lost.png differ diff --git a/resources/image/mask1.png b/resources/image/mask1.png new file mode 100644 index 0000000..84cf5d8 Binary files /dev/null and b/resources/image/mask1.png differ diff --git a/resources/image/mask2.png b/resources/image/mask2.png new file mode 100644 index 0000000..a1bd233 Binary files /dev/null and b/resources/image/mask2.png differ diff --git a/resources/image/movie.png b/resources/image/movie.png new file mode 100644 index 0000000..d5ef2a8 Binary files /dev/null and b/resources/image/movie.png differ diff --git a/resources/image/music.png b/resources/image/music.png new file mode 100644 index 0000000..16e6a29 Binary files /dev/null and b/resources/image/music.png differ diff --git a/resources/image/obj-o000.png b/resources/image/obj-o000.png new file mode 100644 index 0000000..a1b3d70 Binary files /dev/null and b/resources/image/obj-o000.png differ diff --git a/resources/image/obj-o001.png b/resources/image/obj-o001.png new file mode 100644 index 0000000..64bfa07 Binary files /dev/null and b/resources/image/obj-o001.png differ diff --git a/resources/image/obj-o002.png b/resources/image/obj-o002.png new file mode 100644 index 0000000..4c8a64f Binary files /dev/null and b/resources/image/obj-o002.png differ diff --git a/resources/image/obj-o003.png b/resources/image/obj-o003.png new file mode 100644 index 0000000..d35eb5b Binary files /dev/null and b/resources/image/obj-o003.png differ diff --git a/resources/image/obj000.png b/resources/image/obj000.png new file mode 100644 index 0000000..26d6131 Binary files /dev/null and b/resources/image/obj000.png differ diff --git a/resources/image/obj001.png b/resources/image/obj001.png new file mode 100644 index 0000000..266e662 Binary files /dev/null and b/resources/image/obj001.png differ diff --git a/resources/image/obj002.png b/resources/image/obj002.png new file mode 100644 index 0000000..433ba02 Binary files /dev/null and b/resources/image/obj002.png differ diff --git a/resources/image/obj003.png b/resources/image/obj003.png new file mode 100644 index 0000000..8728637 Binary files /dev/null and b/resources/image/obj003.png differ diff --git a/resources/image/play.png b/resources/image/play.png new file mode 100644 index 0000000..cb7ab42 Binary files /dev/null and b/resources/image/play.png differ diff --git a/resources/image/read.png b/resources/image/read.png new file mode 100644 index 0000000..5cb4262 Binary files /dev/null and b/resources/image/read.png differ diff --git a/resources/image/region.png b/resources/image/region.png new file mode 100644 index 0000000..946c3ef Binary files /dev/null and b/resources/image/region.png differ diff --git a/resources/image/setup00.png b/resources/image/setup00.png new file mode 100644 index 0000000..4793560 Binary files /dev/null and b/resources/image/setup00.png differ diff --git a/resources/image/setup01.png b/resources/image/setup01.png new file mode 100644 index 0000000..64a73e2 Binary files /dev/null and b/resources/image/setup01.png differ diff --git a/resources/image/stop000.png b/resources/image/stop000.png new file mode 100644 index 0000000..d4850f9 Binary files /dev/null and b/resources/image/stop000.png differ diff --git a/resources/image/stop001.png b/resources/image/stop001.png new file mode 100644 index 0000000..0abe5c6 Binary files /dev/null and b/resources/image/stop001.png differ diff --git a/resources/image/stop002.png b/resources/image/stop002.png new file mode 100644 index 0000000..4a0167b Binary files /dev/null and b/resources/image/stop002.png differ diff --git a/resources/image/term.png b/resources/image/term.png new file mode 100644 index 0000000..494854e Binary files /dev/null and b/resources/image/term.png differ diff --git a/resources/image/text.png b/resources/image/text.png new file mode 100644 index 0000000..be14abb Binary files /dev/null and b/resources/image/text.png differ diff --git a/resources/image/win.png b/resources/image/win.png new file mode 100644 index 0000000..d523b32 Binary files /dev/null and b/resources/image/win.png differ diff --git a/resources/image/write.png b/resources/image/write.png new file mode 100644 index 0000000..baf2faf Binary files /dev/null and b/resources/image/write.png differ diff --git a/resources/linux/application.desktop.in b/resources/linux/application.desktop.in new file mode 100644 index 0000000..db29df3 --- /dev/null +++ b/resources/linux/application.desktop.in @@ -0,0 +1,10 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Name=@PB_PRODUCT_NAME@ +GenericName=Video Game +Comment=@PB_DESCRIPTION@ +Exec=@PB_EXEC@ +StartupWMClass=@PB_EXEC@ +Icon=@PB_ICON_REF@ +Categories=Game;StrategyGame; diff --git a/resources/linux/icon.svg b/resources/linux/icon.svg new file mode 100644 index 0000000..e49a2ac --- /dev/null +++ b/resources/linux/icon.svg @@ -0,0 +1,1399 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/linux/planetblupi.appdata.xml b/resources/linux/planetblupi.appdata.xml new file mode 100644 index 0000000..e053b48 --- /dev/null +++ b/resources/linux/planetblupi.appdata.xml @@ -0,0 +1,21 @@ + + + planetblupi + MIT + GPL-3.0+ + Planet Blupi + Planet Blupi - A delirious spell-binding game + +

Planet Blupi is a strategy and adventure game. It subtly blends action with thought-provoking challenges. Behind the quiet and gentle facade, you'll enjoy a fascinating diversion full of surprises.

+
+ planetblupi.desktop + http://blupi.org/ + + + http://devel.schroetersa.ch/blupi.org/download/screen/planetblupi.png + + + + planetblupi.desktop + +
\ No newline at end of file diff --git a/resources/movie/history2.mkv b/resources/movie/history2.mkv new file mode 100644 index 0000000..ce3ded1 Binary files /dev/null and b/resources/movie/history2.mkv differ diff --git a/resources/movie/play101.mkv b/resources/movie/play101.mkv new file mode 100644 index 0000000..7c9e5f0 Binary files /dev/null and b/resources/movie/play101.mkv differ diff --git a/resources/movie/play103.mkv b/resources/movie/play103.mkv new file mode 100644 index 0000000..d0d69b3 Binary files /dev/null and b/resources/movie/play103.mkv differ diff --git a/resources/movie/play105.mkv b/resources/movie/play105.mkv new file mode 100644 index 0000000..ed51e42 Binary files /dev/null and b/resources/movie/play105.mkv differ diff --git a/resources/movie/play107.mkv b/resources/movie/play107.mkv new file mode 100644 index 0000000..3b87a64 Binary files /dev/null and b/resources/movie/play107.mkv differ diff --git a/resources/movie/play108.mkv b/resources/movie/play108.mkv new file mode 100644 index 0000000..87a347e Binary files /dev/null and b/resources/movie/play108.mkv differ diff --git a/resources/movie/play110.mkv b/resources/movie/play110.mkv new file mode 100644 index 0000000..9c7113b Binary files /dev/null and b/resources/movie/play110.mkv differ diff --git a/resources/movie/play113.mkv b/resources/movie/play113.mkv new file mode 100644 index 0000000..b1fa7e6 Binary files /dev/null and b/resources/movie/play113.mkv differ diff --git a/resources/movie/play116.mkv b/resources/movie/play116.mkv new file mode 100644 index 0000000..7d45573 Binary files /dev/null and b/resources/movie/play116.mkv differ diff --git a/resources/movie/play118.mkv b/resources/movie/play118.mkv new file mode 100644 index 0000000..6a323f0 Binary files /dev/null and b/resources/movie/play118.mkv differ diff --git a/resources/movie/play119.mkv b/resources/movie/play119.mkv new file mode 100644 index 0000000..b6b080a Binary files /dev/null and b/resources/movie/play119.mkv differ diff --git a/resources/movie/play124.mkv b/resources/movie/play124.mkv new file mode 100644 index 0000000..7c546f5 Binary files /dev/null and b/resources/movie/play124.mkv differ diff --git a/resources/movie/win005.mkv b/resources/movie/win005.mkv new file mode 100644 index 0000000..285e6ec Binary files /dev/null and b/resources/movie/win005.mkv differ diff --git a/resources/movie/win129.mkv b/resources/movie/win129.mkv new file mode 100644 index 0000000..836f6d9 Binary files /dev/null and b/resources/movie/win129.mkv differ diff --git a/resources/music/music000.mid b/resources/music/music000.mid new file mode 100644 index 0000000..172145c Binary files /dev/null and b/resources/music/music000.mid differ diff --git a/resources/music/music000.ogg b/resources/music/music000.ogg new file mode 100644 index 0000000..5c47708 Binary files /dev/null and b/resources/music/music000.ogg differ diff --git a/resources/music/music001.mid b/resources/music/music001.mid new file mode 100644 index 0000000..3a408a2 Binary files /dev/null and b/resources/music/music001.mid differ diff --git a/resources/music/music001.ogg b/resources/music/music001.ogg new file mode 100644 index 0000000..97d95e6 Binary files /dev/null and b/resources/music/music001.ogg differ diff --git a/resources/music/music002.mid b/resources/music/music002.mid new file mode 100644 index 0000000..4d29210 Binary files /dev/null and b/resources/music/music002.mid differ diff --git a/resources/music/music002.ogg b/resources/music/music002.ogg new file mode 100644 index 0000000..0a05f53 Binary files /dev/null and b/resources/music/music002.ogg differ diff --git a/resources/music/music003.mid b/resources/music/music003.mid new file mode 100644 index 0000000..6bcab72 Binary files /dev/null and b/resources/music/music003.mid differ diff --git a/resources/music/music003.ogg b/resources/music/music003.ogg new file mode 100644 index 0000000..de58b17 Binary files /dev/null and b/resources/music/music003.ogg differ diff --git a/resources/music/music004.mid b/resources/music/music004.mid new file mode 100644 index 0000000..b7d4e38 Binary files /dev/null and b/resources/music/music004.mid differ diff --git a/resources/music/music004.ogg b/resources/music/music004.ogg new file mode 100644 index 0000000..7a19d3e Binary files /dev/null and b/resources/music/music004.ogg differ diff --git a/resources/music/music005.mid b/resources/music/music005.mid new file mode 100644 index 0000000..08fba67 Binary files /dev/null and b/resources/music/music005.mid differ diff --git a/resources/music/music005.ogg b/resources/music/music005.ogg new file mode 100644 index 0000000..2dd982a Binary files /dev/null and b/resources/music/music005.ogg differ diff --git a/resources/music/music006.mid b/resources/music/music006.mid new file mode 100644 index 0000000..e511b04 Binary files /dev/null and b/resources/music/music006.mid differ diff --git a/resources/music/music006.ogg b/resources/music/music006.ogg new file mode 100644 index 0000000..057788d Binary files /dev/null and b/resources/music/music006.ogg differ diff --git a/resources/music/music007.mid b/resources/music/music007.mid new file mode 100644 index 0000000..f0853ca Binary files /dev/null and b/resources/music/music007.mid differ diff --git a/resources/music/music007.ogg b/resources/music/music007.ogg new file mode 100644 index 0000000..8d782f2 Binary files /dev/null and b/resources/music/music007.ogg differ diff --git a/resources/music/music008.mid b/resources/music/music008.mid new file mode 100644 index 0000000..ee7d6c3 Binary files /dev/null and b/resources/music/music008.mid differ diff --git a/resources/music/music008.ogg b/resources/music/music008.ogg new file mode 100644 index 0000000..b05d67d Binary files /dev/null and b/resources/music/music008.ogg differ diff --git a/resources/music/music009.mid b/resources/music/music009.mid new file mode 100644 index 0000000..fbb4773 Binary files /dev/null and b/resources/music/music009.mid differ diff --git a/resources/music/music009.ogg b/resources/music/music009.ogg new file mode 100644 index 0000000..a9a0714 Binary files /dev/null and b/resources/music/music009.ogg differ diff --git a/resources/nsis/NSIS.template.in b/resources/nsis/NSIS.template.in new file mode 100644 index 0000000..9a6b03d --- /dev/null +++ b/resources/nsis/NSIS.template.in @@ -0,0 +1,1016 @@ +; CPack install script designed for a nmake build + +;-------------------------------- +; You must define these values + + !define VERSION "@CPACK_PACKAGE_VERSION@" + !define PATCH "@CPACK_PACKAGE_VERSION_PATCH@" + !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@" + +;-------------------------------- +;Variables + + Var MUI_TEMP + Var STARTMENU_FOLDER + Var SV_ALLUSERS + Var START_MENU + Var DO_NOT_ADD_TO_PATH + Var ADD_TO_PATH_ALL_USERS + Var ADD_TO_PATH_CURRENT_USER + Var INSTALL_DESKTOP + Var IS_DEFAULT_INSTALLDIR +;-------------------------------- +;Include Modern UI + + !include "MUI.nsh" + + ;Default installation folder + InstallDir "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" + +;-------------------------------- +;General +!ifdef INNER + OutFile "${TEMPINSTALLER}.exe" + SetCompress off ; for speed +!else + ; Call makensis again, defining INNER. This writes an installer for us which, when + ; it is invoked, will just write the uninstaller to some location, and then exit. + ; Be sure to substitute the name of this script here. + !tempfile TEMPINSTALLER + !tempfile TEMPUNINSTALLER + !system "$\"makensis$\" /DTEMPINSTALLER=$\"${TEMPINSTALLER}$\" /DTEMPUNINSTALLER=$\"${TEMPUNINSTALLER}$\" /DINNER $\"@CPACK_TEMPORARY_DIRECTORY@/../project.nsi$\"" = 0 + + ; So now run that installer we just created as %TEMP%\tempinstaller.exe. Since it + ; calls quit the return value isn't zero. + + !system "$\"${TEMPINSTALLER}.exe$\"" = 2 + + ; That will have written an uninstaller binary for us. Now we sign it with your + ; favourite code signing tool. + + ;!tempfile INCEXIST + ;!system 'if exist "@CPACK_NSIS_SIGN_UNINSTALLER@" echo !define HAVE_SIGN_UNINST > "${INCEXIST}"' + ;!include "${INCEXIST}" + ;!delfile "${INCEXIST}" + ;!ifdef HAVE_SIGN_UNINST + !system 'signtool @CPACK_NSIS_SIGN_UNINSTALLER@ "${TEMPUNINSTALLER}.exe"' = 0 + ;!endif + + ; Good. Now we can carry on writing the real installer. + + ;Name and file + Name "@CPACK_NSIS_PACKAGE_NAME@" + OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@" + + ;Set compression + SetCompressor @CPACK_NSIS_COMPRESSOR@ +!endif + + ;Require administrator access + RequestExecutionLevel admin + +@CPACK_NSIS_DEFINES@ + + !include Sections.nsh + +;--- Component support macros: --- +; The code for the add/remove functionality is from: +; http://nsis.sourceforge.net/Add/Remove_Functionality +; It has been modified slightly and extended to provide +; inter-component dependencies. +Var AR_SecFlags +Var AR_RegFlags +@CPACK_NSIS_SECTION_SELECTED_VARS@ + +; Loads the "selected" flag for the section named SecName into the +; variable VarName. +!macro LoadSectionSelectedIntoVar SecName VarName + SectionGetFlags ${${SecName}} $${VarName} + IntOp $${VarName} $${VarName} & ${SF_SELECTED} ;Turn off all other bits +!macroend + +; Loads the value of a variable... can we get around this? +!macro LoadVar VarName + IntOp $R0 0 + $${VarName} +!macroend + +; Sets the value of a variable +!macro StoreVar VarName IntValue + IntOp $${VarName} 0 + ${IntValue} +!macroend + +!macro InitSection SecName + ; This macro reads component installed flag from the registry and + ;changes checked state of the section on the components page. + ;Input: section index constant name specified in Section command. + + ClearErrors + ;Reading component status from registry + ReadRegDWORD $AR_RegFlags HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" "Installed" + IfErrors "default_${SecName}" + ;Status will stay default if registry value not found + ;(component was never installed) + IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits + SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading default section flags + IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE ;Turn lowest (enabled) bit off + IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags ;Change lowest bit + + ; Note whether this component was installed before + !insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags + IntOp $R0 $AR_RegFlags & $AR_RegFlags + + ;Writing modified flags + SectionSetFlags ${${SecName}} $AR_SecFlags + + "default_${SecName}:" + !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected +!macroend + +!macro FinishSection SecName + ; This macro reads section flag set by user and removes the section + ;if it is not selected. + ;Then it writes component installed flag to registry + ;Input: section index constant name specified in Section command. + + SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading section flags + ;Checking lowest bit: + IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED} + IntCmp $AR_SecFlags 1 "leave_${SecName}" + ;Section is not selected: + ;Calling Section uninstall macro and writing zero installed flag + !insertmacro "Remove_${${SecName}}" + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ + "Installed" 0 + Goto "exit_${SecName}" + + "leave_${SecName}:" + ;Section is selected: + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ + "Installed" 1 + + "exit_${SecName}:" +!macroend + +!macro RemoveSection_CPack SecName + ; This macro is used to call section's Remove_... macro + ;from the uninstaller. + ;Input: section index constant name specified in Section command. + + !insertmacro "Remove_${${SecName}}" +!macroend + +; Determine whether the selection of SecName changed +!macro MaybeSelectionChanged SecName + !insertmacro LoadVar ${SecName}_selected + SectionGetFlags ${${SecName}} $R1 + IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits + + ; See if the status has changed: + IntCmp $R0 $R1 "${SecName}_unchanged" + !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected + + IntCmp $R1 ${SF_SELECTED} "${SecName}_was_selected" + !insertmacro "Deselect_required_by_${SecName}" + goto "${SecName}_unchanged" + + "${SecName}_was_selected:" + !insertmacro "Select_${SecName}_depends" + + "${SecName}_unchanged:" +!macroend +;--- End of Add/Remove macros --- + +;-------------------------------- +;Interface Settings + + !define MUI_HEADERIMAGE + !define MUI_ABORTWARNING + +;---------------------------------------- +; based upon a script of "Written by KiCHiK 2003-01-18 05:57:02" +;---------------------------------------- +!verbose 3 +!include "WinMessages.NSH" +!verbose 4 +;==================================================== +; get_NT_environment +; Returns: the selected environment +; Output : head of the stack +;==================================================== +!macro select_NT_profile UN +Function ${UN}select_NT_profile + StrCmp $ADD_TO_PATH_ALL_USERS "1" 0 environment_single + DetailPrint "Selected environment for all users" + Push "all" + Return + environment_single: + DetailPrint "Selected environment for current user only." + Push "current" + Return +FunctionEnd +!macroend +!insertmacro select_NT_profile "" +!insertmacro select_NT_profile "un." +;---------------------------------------------------- +!define NT_current_env 'HKCU "Environment"' +!define NT_all_env 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' + +!ifndef WriteEnvStr_RegKey + !ifdef ALL_USERS + !define WriteEnvStr_RegKey \ + 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' + !else + !define WriteEnvStr_RegKey 'HKCU "Environment"' + !endif +!endif + +; AddToPath - Adds the given dir to the search path. +; Input - head of the stack +; Note - Win9x systems requires reboot + +Function AddToPath + Exch $0 + Push $1 + Push $2 + Push $3 + + # don't add if the path doesn't exist + IfFileExists "$0\*.*" "" AddToPath_done + + ReadEnvStr $1 PATH + ; if the path is too long for a NSIS variable NSIS will return a 0 + ; length string. If we find that, then warn and skip any path + ; modification as it will trash the existing path. + StrLen $2 $1 + IntCmp $2 0 CheckPathLength_ShowPathWarning CheckPathLength_Done CheckPathLength_Done + CheckPathLength_ShowPathWarning: + Messagebox MB_OK|MB_ICONEXCLAMATION "Warning! PATH too long installer unable to modify PATH!" + Goto AddToPath_done + CheckPathLength_Done: + Push "$1;" + Push "$0;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + Push "$1;" + Push "$0\;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + GetFullPathName /SHORT $3 $0 + Push "$1;" + Push "$3;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + Push "$1;" + Push "$3\;" + Call StrStr + Pop $2 + StrCmp $2 "" "" AddToPath_done + + Call IsNT + Pop $1 + StrCmp $1 1 AddToPath_NT + ; Not on NT + StrCpy $1 $WINDIR 2 + FileOpen $1 "$1\autoexec.bat" a + FileSeek $1 -1 END + FileReadByte $1 $2 + IntCmp $2 26 0 +2 +2 # DOS EOF + FileSeek $1 -1 END # write over EOF + FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n" + FileClose $1 + SetRebootFlag true + Goto AddToPath_done + + AddToPath_NT: + StrCmp $ADD_TO_PATH_ALL_USERS "1" ReadAllKey + ReadRegStr $1 ${NT_current_env} "PATH" + Goto DoTrim + ReadAllKey: + ReadRegStr $1 ${NT_all_env} "PATH" + DoTrim: + StrCmp $1 "" AddToPath_NTdoIt + Push $1 + Call Trim + Pop $1 + StrCpy $0 "$1;$0" + AddToPath_NTdoIt: + StrCmp $ADD_TO_PATH_ALL_USERS "1" WriteAllKey + WriteRegExpandStr ${NT_current_env} "PATH" $0 + Goto DoSend + WriteAllKey: + WriteRegExpandStr ${NT_all_env} "PATH" $0 + DoSend: + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + AddToPath_done: + Pop $3 + Pop $2 + Pop $1 + Pop $0 +FunctionEnd + + +; RemoveFromPath - Remove a given dir from the path +; Input: head of the stack + +Function un.RemoveFromPath + Exch $0 + Push $1 + Push $2 + Push $3 + Push $4 + Push $5 + Push $6 + + IntFmt $6 "%c" 26 # DOS EOF + + Call un.IsNT + Pop $1 + StrCmp $1 1 unRemoveFromPath_NT + ; Not on NT + StrCpy $1 $WINDIR 2 + FileOpen $1 "$1\autoexec.bat" r + GetTempFileName $4 + FileOpen $2 $4 w + GetFullPathName /SHORT $0 $0 + StrCpy $0 "SET PATH=%PATH%;$0" + Goto unRemoveFromPath_dosLoop + + unRemoveFromPath_dosLoop: + FileRead $1 $3 + StrCpy $5 $3 1 -1 # read last char + StrCmp $5 $6 0 +2 # if DOS EOF + StrCpy $3 $3 -1 # remove DOS EOF so we can compare + StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine + StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine + StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine + StrCmp $3 "" unRemoveFromPath_dosLoopEnd + FileWrite $2 $3 + Goto unRemoveFromPath_dosLoop + unRemoveFromPath_dosLoopRemoveLine: + SetRebootFlag true + Goto unRemoveFromPath_dosLoop + + unRemoveFromPath_dosLoopEnd: + FileClose $2 + FileClose $1 + StrCpy $1 $WINDIR 2 + Delete "$1\autoexec.bat" + CopyFiles /SILENT $4 "$1\autoexec.bat" + Delete $4 + Goto unRemoveFromPath_done + + unRemoveFromPath_NT: + StrCmp $ADD_TO_PATH_ALL_USERS "1" unReadAllKey + ReadRegStr $1 ${NT_current_env} "PATH" + Goto unDoTrim + unReadAllKey: + ReadRegStr $1 ${NT_all_env} "PATH" + unDoTrim: + StrCpy $5 $1 1 -1 # copy last char + StrCmp $5 ";" +2 # if last char != ; + StrCpy $1 "$1;" # append ; + Push $1 + Push "$0;" + Call un.StrStr ; Find `$0;` in $1 + Pop $2 ; pos of our dir + StrCmp $2 "" unRemoveFromPath_done + ; else, it is in path + # $0 - path to add + # $1 - path var + StrLen $3 "$0;" + StrLen $4 $2 + StrCpy $5 $1 -$4 # $5 is now the part before the path to remove + StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove + StrCpy $3 $5$6 + + StrCpy $5 $3 1 -1 # copy last char + StrCmp $5 ";" 0 +2 # if last char == ; + StrCpy $3 $3 -1 # remove last char + + StrCmp $ADD_TO_PATH_ALL_USERS "1" unWriteAllKey + WriteRegExpandStr ${NT_current_env} "PATH" $3 + Goto unDoSend + unWriteAllKey: + WriteRegExpandStr ${NT_all_env} "PATH" $3 + unDoSend: + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + unRemoveFromPath_done: + Pop $6 + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Pop $0 +FunctionEnd + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Uninstall sutff +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +########################################### +# Utility Functions # +########################################### + +;==================================================== +; IsNT - Returns 1 if the current system is NT, 0 +; otherwise. +; Output: head of the stack +;==================================================== +; IsNT +; no input +; output, top of the stack = 1 if NT or 0 if not +; +; Usage: +; Call IsNT +; Pop $R0 +; ($R0 at this point is 1 or 0) + +!macro IsNT un +Function ${un}IsNT + Push $0 + ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion + StrCmp $0 "" 0 IsNT_yes + ; we are not NT. + Pop $0 + Push 0 + Return + + IsNT_yes: + ; NT!!! + Pop $0 + Push 1 +FunctionEnd +!macroend +!insertmacro IsNT "" +!insertmacro IsNT "un." + +; StrStr +; input, top of stack = string to search for +; top of stack-1 = string to search in +; output, top of stack (replaces with the portion of the string remaining) +; modifies no other variables. +; +; Usage: +; Push "this is a long ass string" +; Push "ass" +; Call StrStr +; Pop $R0 +; ($R0 at this point is "ass string") + +!macro StrStr un +Function ${un}StrStr +Exch $R1 ; st=haystack,old$R1, $R1=needle + Exch ; st=old$R1,haystack + Exch $R2 ; st=old$R1,old$R2, $R2=haystack + Push $R3 + Push $R4 + Push $R5 + StrLen $R3 $R1 + StrCpy $R4 0 + ; $R1=needle + ; $R2=haystack + ; $R3=len(needle) + ; $R4=cnt + ; $R5=tmp + loop: + StrCpy $R5 $R2 $R3 $R4 + StrCmp $R5 $R1 done + StrCmp $R5 "" done + IntOp $R4 $R4 + 1 + Goto loop +done: + StrCpy $R1 $R2 "" $R4 + Pop $R5 + Pop $R4 + Pop $R3 + Pop $R2 + Exch $R1 +FunctionEnd +!macroend +!insertmacro StrStr "" +!insertmacro StrStr "un." + +Function Trim ; Added by Pelaca + Exch $R1 + Push $R2 +Loop: + StrCpy $R2 "$R1" 1 -1 + StrCmp "$R2" " " RTrim + StrCmp "$R2" "$\n" RTrim + StrCmp "$R2" "$\r" RTrim + StrCmp "$R2" ";" RTrim + GoTo Done +RTrim: + StrCpy $R1 "$R1" -1 + Goto Loop +Done: + Pop $R2 + Exch $R1 +FunctionEnd + +Function ConditionalAddToRegisty + Pop $0 + Pop $1 + StrCmp "$0" "" ConditionalAddToRegisty_EmptyString + WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" \ + "$1" "$0" + ;MessageBox MB_OK "Set Registry: '$1' to '$0'" + DetailPrint "Set install registry entry: '$1' to '$0'" + ConditionalAddToRegisty_EmptyString: +FunctionEnd + +;-------------------------------- + +!ifdef CPACK_USES_DOWNLOAD +Function DownloadFile + IfFileExists $INSTDIR\* +2 + CreateDirectory $INSTDIR + Pop $0 + + ; Skip if already downloaded + IfFileExists $INSTDIR\$0 0 +2 + Return + + StrCpy $1 "@CPACK_DOWNLOAD_SITE@" + + try_again: + NSISdl::download "$1/$0" "$INSTDIR\$0" + + Pop $1 + StrCmp $1 "success" success + StrCmp $1 "Cancelled" cancel + MessageBox MB_OK "Download failed: $1" + cancel: + Return + success: +FunctionEnd +!endif + +;-------------------------------- +; Installation types +@CPACK_NSIS_INSTALLATION_TYPES@ + +;-------------------------------- +; Component sections +@CPACK_NSIS_COMPONENT_SECTIONS@ + +;-------------------------------- +; Define some macro setting for the gui +@CPACK_NSIS_INSTALLER_MUI_ICON_CODE@ +@CPACK_NSIS_INSTALLER_ICON_CODE@ +@CPACK_NSIS_INSTALLER_MUI_WELCOMEFINISH_CODE@ +@CPACK_NSIS_INSTALLER_MUI_UNWELCOMEFINISH_CODE@ +@CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@ +@CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE@ + +;-------------------------------- +;Pages + !insertmacro MUI_PAGE_WELCOME + + !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@" + Page custom InstallOptionsPage + !insertmacro MUI_PAGE_DIRECTORY + + ;Start Menu Folder Page Configuration + !define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX" + !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" + !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" + !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER + + @CPACK_NSIS_PAGE_COMPONENTS@ + + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_PAGE_FINISH + +!ifdef INNER + !insertmacro MUI_UNPAGE_CONFIRM + !insertmacro MUI_UNPAGE_INSTFILES +!endif + +;-------------------------------- +;Languages + + !insertmacro MUI_LANGUAGE "English" ;first language is the default language + !insertmacro MUI_LANGUAGE "Albanian" + !insertmacro MUI_LANGUAGE "Arabic" + !insertmacro MUI_LANGUAGE "Basque" + !insertmacro MUI_LANGUAGE "Belarusian" + !insertmacro MUI_LANGUAGE "Bosnian" + !insertmacro MUI_LANGUAGE "Breton" + !insertmacro MUI_LANGUAGE "Bulgarian" + !insertmacro MUI_LANGUAGE "Croatian" + !insertmacro MUI_LANGUAGE "Czech" + !insertmacro MUI_LANGUAGE "Danish" + !insertmacro MUI_LANGUAGE "Dutch" + !insertmacro MUI_LANGUAGE "Estonian" + !insertmacro MUI_LANGUAGE "Farsi" + !insertmacro MUI_LANGUAGE "Finnish" + !insertmacro MUI_LANGUAGE "French" + !insertmacro MUI_LANGUAGE "German" + !insertmacro MUI_LANGUAGE "Greek" + !insertmacro MUI_LANGUAGE "Hebrew" + !insertmacro MUI_LANGUAGE "Hungarian" + !insertmacro MUI_LANGUAGE "Icelandic" + !insertmacro MUI_LANGUAGE "Indonesian" + !insertmacro MUI_LANGUAGE "Irish" + !insertmacro MUI_LANGUAGE "Italian" + !insertmacro MUI_LANGUAGE "Japanese" + !insertmacro MUI_LANGUAGE "Korean" + !insertmacro MUI_LANGUAGE "Kurdish" + !insertmacro MUI_LANGUAGE "Latvian" + !insertmacro MUI_LANGUAGE "Lithuanian" + !insertmacro MUI_LANGUAGE "Luxembourgish" + !insertmacro MUI_LANGUAGE "Macedonian" + !insertmacro MUI_LANGUAGE "Malay" + !insertmacro MUI_LANGUAGE "Mongolian" + !insertmacro MUI_LANGUAGE "Norwegian" + !insertmacro MUI_LANGUAGE "Polish" + !insertmacro MUI_LANGUAGE "Portuguese" + !insertmacro MUI_LANGUAGE "PortugueseBR" + !insertmacro MUI_LANGUAGE "Romanian" + !insertmacro MUI_LANGUAGE "Russian" + !insertmacro MUI_LANGUAGE "Serbian" + !insertmacro MUI_LANGUAGE "SerbianLatin" + !insertmacro MUI_LANGUAGE "SimpChinese" + !insertmacro MUI_LANGUAGE "Slovak" + !insertmacro MUI_LANGUAGE "Slovenian" + !insertmacro MUI_LANGUAGE "Spanish" + !insertmacro MUI_LANGUAGE "Swedish" + !insertmacro MUI_LANGUAGE "Thai" + !insertmacro MUI_LANGUAGE "TradChinese" + !insertmacro MUI_LANGUAGE "Turkish" + !insertmacro MUI_LANGUAGE "Ukrainian" + !insertmacro MUI_LANGUAGE "Welsh" + + +;-------------------------------- +;Reserve Files + + ;These files should be inserted before other files in the data block + ;Keep these lines before any File command + ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA) + + ReserveFile "NSIS.InstallOptions.ini" + !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS + +;-------------------------------- +;Installer Sections + +Section "-Core installation" + ;Use the entire tree produced by the INSTALL target. Keep the + ;list of directories here in sync with the RMDir commands below. + SetOutPath "$INSTDIR" + @CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS@ + @CPACK_NSIS_FULL_INSTALL@ + + ;Store installation folder + WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR + + ;Create uninstaller +!ifndef INNER + ; this packages the signed uninstaller + File "/oname=Uninstall.exe" "${TEMPUNINSTALLER}.exe" +!endif + Push "DisplayName" + Push "@CPACK_NSIS_DISPLAY_NAME@" + Call ConditionalAddToRegisty + Push "DisplayVersion" + Push "@CPACK_PACKAGE_VERSION@" + Call ConditionalAddToRegisty + Push "Publisher" + Push "@CPACK_PACKAGE_VENDOR@" + Call ConditionalAddToRegisty + Push "UninstallString" + Push "$INSTDIR\Uninstall.exe" + Call ConditionalAddToRegisty + Push "NoRepair" + Push "1" + Call ConditionalAddToRegisty + + !ifdef CPACK_NSIS_ADD_REMOVE + ;Create add/remove functionality + Push "ModifyPath" + Push "$INSTDIR\AddRemove.exe" + Call ConditionalAddToRegisty + !else + Push "NoModify" + Push "1" + Call ConditionalAddToRegisty + !endif + + ; Optional registration + Push "DisplayIcon" + Push "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@" + Call ConditionalAddToRegisty + Push "HelpLink" + Push "@CPACK_NSIS_HELP_LINK@" + Call ConditionalAddToRegisty + Push "URLInfoAbout" + Push "@CPACK_NSIS_URL_INFO_ABOUT@" + Call ConditionalAddToRegisty + Push "Contact" + Push "@CPACK_NSIS_CONTACT@" + Call ConditionalAddToRegisty + !insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP "NSIS.InstallOptions.ini" "Field 5" "State" + !insertmacro MUI_STARTMENU_WRITE_BEGIN Application + + ;Create shortcuts + CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" +@CPACK_NSIS_CREATE_ICONS@ +@CPACK_NSIS_CREATE_ICONS_EXTRA@ + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" + + ;Read a value from an InstallOptions INI file + !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State" + !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS "NSIS.InstallOptions.ini" "Field 3" "State" + !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER "NSIS.InstallOptions.ini" "Field 4" "State" + + ; Write special uninstall registry entries + Push "StartMenu" + Push "$STARTMENU_FOLDER" + Call ConditionalAddToRegisty + Push "DoNotAddToPath" + Push "$DO_NOT_ADD_TO_PATH" + Call ConditionalAddToRegisty + Push "AddToPathAllUsers" + Push "$ADD_TO_PATH_ALL_USERS" + Call ConditionalAddToRegisty + Push "AddToPathCurrentUser" + Push "$ADD_TO_PATH_CURRENT_USER" + Call ConditionalAddToRegisty + Push "InstallToDesktop" + Push "$INSTALL_DESKTOP" + Call ConditionalAddToRegisty + + !insertmacro MUI_STARTMENU_WRITE_END + +@CPACK_NSIS_EXTRA_INSTALL_COMMANDS@ + +SectionEnd + +Section "-Add to path" + Push $INSTDIR\bin + StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 doNotAddToPath + StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0 + Call AddToPath + doNotAddToPath: +SectionEnd + +;-------------------------------- +; Create custom pages +Function InstallOptionsPage + !insertmacro MUI_HEADER_TEXT "Install Options" "Choose options for installing @CPACK_NSIS_PACKAGE_NAME@" + !insertmacro MUI_INSTALLOPTIONS_DISPLAY "NSIS.InstallOptions.ini" + +FunctionEnd + +;-------------------------------- +; determine admin versus local install +Function un.onInit + + ClearErrors + UserInfo::GetName + IfErrors noLM + Pop $0 + UserInfo::GetAccountType + Pop $1 + StrCmp $1 "Admin" 0 +3 + SetShellVarContext all + ;MessageBox MB_OK 'User "$0" is in the Admin group' + Goto done + StrCmp $1 "Power" 0 +3 + SetShellVarContext all + ;MessageBox MB_OK 'User "$0" is in the Power Users group' + Goto done + + noLM: + ;Get installation folder from registry if available + + done: + +FunctionEnd + +;--- Add/Remove callback functions: --- +!macro SectionList MacroName + ;This macro used to perform operation on multiple sections. + ;List all of your components in following manner here. +@CPACK_NSIS_COMPONENT_SECTION_LIST@ +!macroend + +Section -FinishComponents + ;Removes unselected components and writes component status to registry + !insertmacro SectionList "FinishSection" + +!ifdef CPACK_NSIS_ADD_REMOVE + ; Get the name of the installer executable + System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1' + StrCpy $R3 $R0 + + ; Strip off the last 13 characters, to see if we have AddRemove.exe + StrLen $R1 $R0 + IntOp $R1 $R0 - 13 + StrCpy $R2 $R0 13 $R1 + StrCmp $R2 "AddRemove.exe" addremove_installed + + ; We're not running AddRemove.exe, so install it + CopyFiles $R3 $INSTDIR\AddRemove.exe + + addremove_installed: +!endif +SectionEnd +;--- End of Add/Remove callback functions --- + +;-------------------------------- +; Component dependencies +Function .onSelChange + !insertmacro SectionList MaybeSelectionChanged +FunctionEnd + +;-------------------------------- +;Uninstaller Section + +!ifdef INNER +Section "Uninstall" + ReadRegStr $START_MENU SHCTX \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "StartMenu" + ;MessageBox MB_OK "Start menu is in: $START_MENU" + ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "DoNotAddToPath" + ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathAllUsers" + ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathCurrentUser" + ;MessageBox MB_OK "Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS" + ReadRegStr $INSTALL_DESKTOP SHCTX \ + "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "InstallToDesktop" + ;MessageBox MB_OK "Install to desktop: $INSTALL_DESKTOP " + +@CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@ + + ;Remove files we installed. + ;Keep the list of directories here in sync with the File commands above. +@CPACK_NSIS_DELETE_FILES@ +@CPACK_NSIS_DELETE_DIRECTORIES@ + +!ifdef CPACK_NSIS_ADD_REMOVE + ;Remove the add/remove program + Delete "$INSTDIR\AddRemove.exe" +!endif + + ;Remove the uninstaller itself. + Delete "$INSTDIR\Uninstall.exe" + DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" + + ;Remove the installation directory if it is empty. + RMDir "$INSTDIR" + + ; Remove the registry entries. + DeleteRegKey SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" + + ; Removes all optional components + !insertmacro SectionList "RemoveSection_CPack" + + !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP + + Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" +@CPACK_NSIS_DELETE_ICONS@ +@CPACK_NSIS_DELETE_ICONS_EXTRA@ + + ;Delete empty start menu parent diretories + StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" + + startMenuDeleteLoop: + ClearErrors + RMDir $MUI_TEMP + GetFullPathName $MUI_TEMP "$MUI_TEMP\.." + + IfErrors startMenuDeleteLoopDone + + StrCmp "$MUI_TEMP" "$SMPROGRAMS" startMenuDeleteLoopDone startMenuDeleteLoop + startMenuDeleteLoopDone: + + ; If the user changed the shortcut, then untinstall may not work. This should + ; try to fix it. + StrCpy $MUI_TEMP "$START_MENU" + Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" +@CPACK_NSIS_DELETE_ICONS_EXTRA@ + + ;Delete empty start menu parent diretories + StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" + + secondStartMenuDeleteLoop: + ClearErrors + RMDir $MUI_TEMP + GetFullPathName $MUI_TEMP "$MUI_TEMP\.." + + IfErrors secondStartMenuDeleteLoopDone + + StrCmp "$MUI_TEMP" "$SMPROGRAMS" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop + secondStartMenuDeleteLoopDone: + + DeleteRegKey /ifempty SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" + + Push $INSTDIR\bin + StrCmp $DO_NOT_ADD_TO_PATH_ "1" doNotRemoveFromPath 0 + Call un.RemoveFromPath + doNotRemoveFromPath: +SectionEnd +!endif + +;-------------------------------- +; determine admin versus local install +; Is install for "AllUsers" or "JustMe"? +; Default to "JustMe" - set to "AllUsers" if admin or on Win9x +; This function is used for the very first "custom page" of the installer. +; This custom page does not show up visibly, but it executes prior to the +; first visible page and sets up $INSTDIR properly... +; Choose different default installation folder based on SV_ALLUSERS... +; "Program Files" for AllUsers, "My Documents" for JustMe... + +Function .onInit +!ifdef INNER + ; If INNER is defined, then we aren't supposed to do anything except write out + ; the installer. This is better than processing a command line option as it means + ; this entire code path is not present in the final (real) installer. + + WriteUninstaller "${TEMPUNINSTALLER}.exe" + Quit ; just bail out quickly when running the "inner" installer +!endif + StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst + + ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "UninstallString" + StrCmp $0 "" inst + + MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \ + "@CPACK_NSIS_PACKAGE_NAME@ is already installed. $\n$\nDo you want to uninstall the old version before installing the new one?" \ + /SD IDYES IDYES uninst IDNO inst + Abort + +;Run the uninstaller +uninst: + ClearErrors + StrLen $2 "\Uninstall.exe" + StrCpy $3 $0 -$2 # remove "\Uninstall.exe" from UninstallString to get path + ExecWait '"$0" /S _?=$3' ;Do not copy the uninstaller to a temp file + + IfErrors uninst_failed inst +uninst_failed: + MessageBox MB_OK|MB_ICONSTOP "Uninstall failed." + Abort + + +inst: + ; Reads components status for registry + !insertmacro SectionList "InitSection" + + ; check to see if /D has been used to change + ; the install directory by comparing it to the + ; install directory that is expected to be the + ; default + StrCpy $IS_DEFAULT_INSTALLDIR 0 + StrCmp "$INSTDIR" "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" 0 +2 + StrCpy $IS_DEFAULT_INSTALLDIR 1 + + StrCpy $SV_ALLUSERS "JustMe" + ; if default install dir then change the default + ; if it is installed for JustMe + StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 + StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@" + + ClearErrors + UserInfo::GetName + IfErrors noLM + Pop $0 + UserInfo::GetAccountType + Pop $1 + StrCmp $1 "Admin" 0 +4 + SetShellVarContext all + ;MessageBox MB_OK 'User "$0" is in the Admin group' + StrCpy $SV_ALLUSERS "AllUsers" + Goto done + StrCmp $1 "Power" 0 +4 + SetShellVarContext all + ;MessageBox MB_OK 'User "$0" is in the Power Users group' + StrCpy $SV_ALLUSERS "AllUsers" + Goto done + + noLM: + StrCpy $SV_ALLUSERS "AllUsers" + ;Get installation folder from registry if available + + done: + StrCmp $SV_ALLUSERS "AllUsers" 0 +3 + StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 + StrCpy $INSTDIR "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" + + StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 noOptionsPage + !insertmacro MUI_INSTALLOPTIONS_EXTRACT "NSIS.InstallOptions.ini" + + noOptionsPage: +FunctionEnd diff --git a/resources/nsis/bootstrap.sh b/resources/nsis/bootstrap.sh new file mode 100755 index 0000000..1cf1390 --- /dev/null +++ b/resources/nsis/bootstrap.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +CMAKE_VERSION=3.12 + +mv /C/msys64/mingw64/share/cmake-$CMAKE_VERSION/Modules/NSIS.template.in /C/msys64/mingw64/share/cmake-$CMAKE_VERSION/Modules/NSIS.template.in.orig +mv /C/msys64/mingw32/share/cmake-$CMAKE_VERSION/Modules/NSIS.template.in /C/msys64/mingw32/share/cmake-$CMAKE_VERSION/Modules/NSIS.template.in.orig +cp $(dirname $0)/NSIS.template.in /C/msys64/mingw64/share/cmake-$CMAKE_VERSION/Modules/NSIS.template.in +cp $(dirname $0)/NSIS.template.in /C/msys64/mingw32/share/cmake-$CMAKE_VERSION/Modules/NSIS.template.in diff --git a/resources/nsis/installer.bmp b/resources/nsis/installer.bmp new file mode 100644 index 0000000..d5f8f42 Binary files /dev/null and b/resources/nsis/installer.bmp differ diff --git a/resources/nsis/installer.png b/resources/nsis/installer.png new file mode 100644 index 0000000..34c3f6b Binary files /dev/null and b/resources/nsis/installer.png differ diff --git a/resources/nsis/installer.svg b/resources/nsis/installer.svg new file mode 100644 index 0000000..398feb4 --- /dev/null +++ b/resources/nsis/installer.svg @@ -0,0 +1,268 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/resources/po/de.po b/resources/po/de.po new file mode 100644 index 0000000..84e3cf9 --- /dev/null +++ b/resources/po/de.po @@ -0,0 +1,995 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-08-08 07:29+0200\n" +"PO-Revision-Date: 2017-12-14 23:15+0100\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.0.5\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid " - FFmpeg (LGPLv2.1)" +msgstr " - FFmpeg (LGPLv2.1)" + +msgid " - GNU/gettext and GNU/libiconv (GPLv3)" +msgstr " - GNU/gettext und GNU/libiconv (GPLv3)" + +msgid " - SDL2, SDL2_image and SDL2_mixer (zlib license)" +msgstr " - SDL2, SDL2_image und SDL2_mixer (zlib Lizenz)" + +msgid " - SDL_kitchensink (MIT)" +msgstr " - SDL_kitchensink (MIT)" + +msgid " - argagg (MIT)" +msgstr " - argagg (MIT)" + +msgid " - libasound (LGPLv2.1)" +msgstr " - libasound (LGPLv2.1)" + +msgid " - libcurl (MIT/X derivate)" +msgstr " - libcurl (MIT/X Derivatlizenz)" + +msgid " - libogg and libvorbis (own license)" +msgstr " - libogg and libvorbis (Eigene Lizenz)" + +msgid " - libpng (own license)" +msgstr " - libpng (Eigene Lizenz)" + +msgid " - libpulse (LGPLv2.1)" +msgstr " - libpulse (LGPLv2.1)" + +msgid " - libsndfile (LGPLv3)" +msgstr " - libsndfile (LGPLv3)" + +msgid " - zlib (own license)" +msgstr " - zlib (Eigene Lizenz)" + +msgid "(isolated tower)" +msgstr "(Alleinstehender Wachturm)" + +msgid "" +"1: Cut down a tree \n" +"2: Build a bridge" +msgstr "" +"1: Baum fällen\n" +"2: Brücke bauen" + +msgid "" +"1: Cut down a tree \n" +"2: Make a boat" +msgstr "" +"1: Baum fällen\n" +"2: Boot bauen" + +msgid "" +"1: Cut down a tree \n" +"2: Make a palisade" +msgstr "" +"1: Baum fällen\n" +"2: Palissade bauen" + +msgid "" +"1: Extract iron\n" +"2: Make a Jeep" +msgstr "" +"1: Eisen abbauen\n" +"2: Jeep bauen" + +msgid "" +"1: Extract iron\n" +"2: Make a bomb" +msgstr "" +"1: Eisen abbauen\n" +"2: Zeitbombe bauen" + +msgid "" +"1: Extract iron\n" +"2: Make an armour" +msgstr "" +"1: Eisen abbauen\n" +"2: Rüstung bauen" + +msgid "" +"1: Grow tomatoes\n" +"2: Eat" +msgstr "" +"1: Tomaten anbauen...\n" +"2: Essen" + +msgid "" +"1: Make a bunch\n" +"2: Transform" +msgstr "" +"1: Blumenstrauss binden\n" +"2: Verarbeiten" + +msgid "" +"1: Take\n" +"2: Build a bridge" +msgstr "" +"1: Nehmen\n" +"2: Brücke bauen" + +msgid "" +"1: Take\n" +"2: Build palisade" +msgstr "" +"1: Nehmen\n" +"2: Palissade bauen" + +msgid "" +"1: Take\n" +"2: Make a boat" +msgstr "" +"1: Bretter nehmen\n" +"2: Boot bauen" + +msgid "" +"1: Take\n" +"2: Transform" +msgstr "" +"1: Nehmen\n" +"2: Verarbeiten" + +msgid "" +"1|Drop planks on striped \n" +"1|paving stones." +msgstr "" +"1|Bretter auf die\n" +"1|gestreiften Quadrate legen." + +msgid "" +"1|Drop platinium on striped \n" +"1|paving stones." +msgstr "" +"1|Platinium auf die\n" +"1|gestreiften Quadrate legen." + +msgid "" +"1|Drop tomatoes on striped \n" +"1|paving stones." +msgstr "" +"1|Tomaten auf die\n" +"1|gestreiften Quadrate legen." + +msgid "" +"1|Each Blupi in\n" +"1|his house." +msgstr "" +"1|Jeder Blupi\n" +"1|in seinem Haus." + +msgid "" +"1|Go on striped\n" +"1|paving stones." +msgstr "" +"1|Auf die gestreiften\n" +"1|Quadrate gehen." + +msgid "1|Goal :" +msgstr "1|Ziel :" + +msgid "" +"1|Kill all\n" +"1|enemies !" +msgstr "1|Alle Feinde zerstören !" + +msgid "" +"1|Resist until\n" +"1|fire extinction ..." +msgstr "" +"1|Solange überleben bis\n" +"1|das Feuer ausgegangen ist." + +# Plural +#, c-format +msgid "" +"1|The Blupi population must\n" +"1|be of at least %d Blupi." +msgstr "" +"1|Die Blupibevölkerung\n" +"1|muss mindestens %d Blupi\n" +"1|betragen." + +msgid "" +"1|The robot must reach\n" +"1|the striped paving stones." +msgstr "" +"1|Der Roboter muss die\n" +"1|gestreiften Quadrate erreichen." + +msgid "Aliasing" +msgstr "" + +msgid "All licenses are available under share/doc/planetblupi/copyright" +msgstr "Alle Lizenzen sind unter share/doc/planetblupi/copyright" + +msgid "Already two teleporters" +msgstr "Es gibt schon 2 Beammaschinen" + +msgid "Another mistake..." +msgstr "Das war leider nicht die richtige Lösung !" + +msgid "Anti-aliasing" +msgstr "" + +msgid "Armour" +msgstr "Rüstung" + +msgid "Available buttons" +msgstr "" +"Zur Verfügung\n" +"stehende Knöpfe" + +msgid "Bang, failed again !" +msgstr "Das war mal wieder nichts !" + +msgid "Bank" +msgstr "Ufer" + +msgid "Blow up" +msgstr "Zünden" + +msgid "Blupi" +msgstr "Blupi" + +msgid "Blupi in house" +msgstr "Blupi im Haus" + +msgid "Blupi on striped paving stones" +msgstr "Blupi auf gestreiften Quadraten" + +msgid "Blupi's energy" +msgstr "Blupis Energie" + +msgid "Blupi's house" +msgstr "Blupis Haus" + +msgid "Boat" +msgstr "Boot" + +msgid "Bouncing bomb" +msgstr "Springende Bombe" + +msgid "Bridge" +msgstr "Brücke" + +msgid "Bridge finished" +msgstr "Brücke schon fertig" + +msgid "Buildings" +msgstr "Gebäude" + +msgid "Bulldozer" +msgstr "Planierraupe" + +msgid "Bunch of flowers" +msgstr "Blumenstrauss" + +msgid "Burnt ground" +msgstr "Verbrannter Untergrund" + +msgid "Cancel last operation" +msgstr "Letzten Befehl rückgängig machen" + +msgid "Carve a rock" +msgstr "Stein bearbeiten" + +msgid "Carve rocks" +msgstr "Steine bearbeiten" + +#, fuzzy +msgid "" +"Change the\n" +"display mode" +msgstr "" +"Fentergrösse\n" +"anpassen" + +#, fuzzy +msgid "" +"Change the\n" +"render quality" +msgstr "" +"Fentergrösse\n" +"anpassen" + +msgid "" +"Change the\n" +"window size" +msgstr "" +"Fentergrösse\n" +"anpassen" + +msgid "" +"Choose the\n" +"music format" +msgstr "" + +msgid "Construct this game" +msgstr "Diese Mission konstruieren" + +msgid "Construction" +msgstr "Konstruktion" + +msgid "Construction number" +msgstr "Konstruktion Nummer" + +msgid "Continue this game" +msgstr "Mission weiterspielen" + +msgid "Cut down a tree" +msgstr "Baum fällen" + +msgid "Cut down trees" +msgstr "Bäume fällen" + +msgid "Decorative plants" +msgstr "Pflanzen" + +msgid "Delete figure" +msgstr "Figur löschen" + +msgid "Delete fire" +msgstr "Feuer löschen" + +msgid "Delete item" +msgstr "Gegenstand löschen" + +msgid "Demo" +msgstr "Demo" + +msgid "Desert" +msgstr "Wüste" + +msgid "Desktop" +msgstr "" + +msgid "Desktop mode" +msgstr "" + +msgid "Difficult" +msgstr "Schwer" + +msgid "Disable anti-aliasing" +msgstr "" + +msgid "Drink" +msgstr "Trinken" + +msgid "Drop" +msgstr "Hinlegen" + +msgid "Dynamite" +msgstr "Dynamitstangen" + +msgid "E" +msgstr "O" + +msgid "Easy" +msgstr "Leicht" + +msgid "Eat" +msgstr "Essen" + +msgid "Eggs" +msgstr "Eier" + +msgid "Electrocutor" +msgstr "Elektrisiermaschine" + +msgid "Enable anti-aliasing" +msgstr "" + +msgid "Ending conditions" +msgstr "" +"Bedingungen für\n" +"Ende der Mission" + +msgid "Enemy barrier" +msgstr "Feindlicher Zaun" + +msgid "Enemy buildings" +msgstr "Feindliches Gebäude" + +msgid "Enemy construction" +msgstr "Feindliche Einrichtung" + +msgid "Enemy ground" +msgstr "Feindesgrund" + +msgid "Enemy rocket" +msgstr "Feindliche Rakete" + +msgid "Excellent..." +msgstr "Ausgezeichnet" + +msgid "Extract iron" +msgstr "Eisen abbauen" + +msgid "Faster" +msgstr "Schneller" + +msgid "Finish" +msgstr "Beenden" + +msgid "Fire" +msgstr "Feuer" + +msgid "Fire out" +msgstr "Feuer ausgegangen" + +msgid "Flag" +msgstr "Wimpel" + +msgid "Flowers" +msgstr "Blumen" + +msgid "Forest" +msgstr "Wald" + +msgid "Forest under snow" +msgstr "Verschneiter Wald" + +msgid "Fullscreen" +msgstr "Vollbildschirm" + +msgid "Game paused" +msgstr "Pause" + +msgid "Garden shed" +msgstr "Gartenhäuschen" + +msgid "" +"Global game\n" +"speed" +msgstr "" +"Globale\n" +"Geschwindigkeit\n" +"des Spiels" + +msgid "Global settings" +msgstr "Allgemeine Einstellungen" + +msgid "Go" +msgstr "Gehen" + +msgid "Grow tomatoes" +msgstr "Garten anlegen" + +msgid "Help" +msgstr "Hilfe" + +msgid "Help number" +msgstr "Hilfe Nummer" + +msgid "Helper robot" +msgstr "Hilfsroboter" + +msgid "Ice" +msgstr "Eis" + +msgid "Impossible" +msgstr "Hier nicht möglich" + +#, c-format +msgid "Impossible to win if less than %d Blupi" +msgstr "Gewinnen unmöglich wenn weniger als %d Blupi" + +msgid "Inadequate ground" +msgstr "Untergrund nicht geeignet" + +msgid "Increase volume" +msgstr "Lauter" + +msgid "Increase window size" +msgstr "Fenstergrösse vergrössern" + +msgid "Incubator" +msgstr "Brutplatz" + +msgid "Incubator or teleporter" +msgstr "Brutplatz oder Beammaschine" + +msgid "Inflammable ground" +msgstr "Brennbarer Untergrund" + +msgid "Insert CD-Rom Planet Blupi and wait a few seconds..." +msgstr "" +"Füge die Planet Blupi CD-Rom in das Laufwerk ein und warte einige " +"Sekunden ..." + +msgid "" +"Interface language\n" +"and sounds" +msgstr "" +"Sprache\n" +"und Sound" + +msgid "Interrupt" +msgstr "Halt" + +msgid "Iron" +msgstr "Eisenerz" + +msgid "Items" +msgstr "Gegenstände" + +msgid "Jeep" +msgstr "Jeep" + +msgid "Laboratory" +msgstr "Labor" + +msgid "Last construction resolved !" +msgstr "Letzte konstruierte Mission beendet." + +msgid "Leave Jeep" +msgstr "Aussteigen" + +msgid "Legacy" +msgstr "" + +msgid "Legacy mode (640x480)" +msgstr "" + +#, c-format +msgid "Lost if less than %d Blupi" +msgstr "Verloren sobald weniger als %d Blupi" + +msgid "Make a Jeep" +msgstr "Jeep bauen" + +msgid "Make a helper robot" +msgstr "Roboter bauen" + +msgid "Make a time bomb" +msgstr "Zeitbombe bauen" + +msgid "Make armour" +msgstr "Rüstung bauen" + +msgid "Make bunch of flowers" +msgstr "Blumenstrauss machen" + +msgid "Make bunches of flowers" +msgstr "Blumensträusse machen" + +msgid "Master robot" +msgstr "Roboterchef" + +msgid "Medical potion" +msgstr "Medikament" + +msgid "Midi" +msgstr "Midi" + +msgid "Mine" +msgstr "Bergwerk" + +msgid "Miscellaneous ground" +msgstr "Gemischter Untergrund" + +msgid "Mission number" +msgstr "Mission Nummer" + +msgid "Mission over..." +msgstr "Auftrag erfüllt" + +msgid "Missions" +msgstr "Missionen" + +msgid "" +"Music\n" +"volume" +msgstr "" +"Lautstärke\n" +"der Musik" + +msgid "Music choice" +msgstr "Auswahl der Musik" + +msgid "Music number 1" +msgstr "Musik Nummer 1" + +msgid "Music number 10" +msgstr "Musik Nummer 10" + +msgid "Music number 2" +msgstr "Musik Nummer 2" + +msgid "Music number 3" +msgstr "Musik Nummer 3" + +msgid "Music number 4" +msgstr "Musik Nummer 4" + +msgid "Music number 5" +msgstr "Musik Nummer 5" + +msgid "Music number 6" +msgstr "Musik Nummer 6" + +msgid "Music number 7" +msgstr "Musik Nummer 7" + +msgid "Music number 8" +msgstr "Musik Nummer 9" + +msgid "Music number 9" +msgstr "Musik Nummer 9" + +msgid "N" +msgstr "N" + +#, c-format +msgid "New version available for download on www.blupi.org (v%s)" +msgstr "Neue Version (v%s) auf www.blupi.org zum Download verfügbar" + +msgid "Next game" +msgstr "Nächste Mission" + +msgid "Next language" +msgstr "Nächste Sprache" + +msgid "Next page" +msgstr "Nächste Seite" + +msgid "No" +msgstr "Nein" + +msgid "No more enemies" +msgstr "Keine Feinde mehr" + +msgid "No music" +msgstr "Keine Musik" + +msgid "No video" +msgstr "Keine Videosequenzen" + +msgid "No, not that way !" +msgstr "Aber nein, doch nicht so..." + +msgid "No, wrong way ..." +msgstr "Nein, so geht das leider nicht !" + +msgid "None" +msgstr "Keine" + +msgid "Normal ground" +msgstr "Normaler Untergrund" + +msgid "Not available" +msgstr "" + +msgid "Not enough energy" +msgstr "Ungenügend Energie" + +msgid "Now go on mission." +msgstr "Du kannst jetzt mit den Missionen beginnen." + +msgid "Occupied ground" +msgstr "Untergrund schon besetzt" + +msgid "Ogg" +msgstr "Ogg" + +msgid "Open another game" +msgstr "Gespeicherte Mission öffnen" + +msgid "Opposite bank no good" +msgstr "Anderes Ufer nicht OK" + +msgid "Palisade" +msgstr "Palisade" + +msgid "Paving stones" +msgstr "Platten" + +msgid "Planet Blupi" +msgstr "Planet Blupi" + +msgid "Planet Blupi -- stop" +msgstr "Planet Blupi -- Halt" + +msgid "Planks" +msgstr "Bretter" + +msgid "Planks on striped paving stones" +msgstr "Bretter auf gestreiften Quadraten" + +msgid "Platinium" +msgstr "Platinium" + +msgid "Platinium on striped paving stones" +msgstr "Platinium auf gestreiften Quadraten" + +msgid "Play this game" +msgstr "Diese Mission spielen" + +msgid "Poison" +msgstr "Gift" + +msgid "Prairie" +msgstr "Wiese" + +msgid "Previous game" +msgstr "Vorhergehende Mission" + +msgid "Previous language" +msgstr "Vorherige Sprache" + +msgid "Previous page" +msgstr "Vorhergehende Seite" + +msgid "Prospect for iron" +msgstr "Eisen suchen" + +msgid "Protection tower" +msgstr "Wachturm" + +msgid "Quit" +msgstr "Aussteigen" + +msgid "Quit Planet Blupi" +msgstr "Planet Blupi beenden" + +msgid "Quit construction" +msgstr "Konstruktion beenden" + +msgid "Quit this game" +msgstr "Mission aufgeben" + +msgid "REC" +msgstr "REC" + +msgid "Reduce volume" +msgstr "Leiser" + +msgid "Reduce window size" +msgstr "Fenstergrösse verkleinern" + +msgid "Repeat" +msgstr "Wiederholen" + +msgid "Restart this game" +msgstr "Neu Anfangen" + +msgid "Robot on striped paving stones" +msgstr "Roboter auf gestreiften Quadraten" + +msgid "Rocks" +msgstr "Felsen" + +msgid "S" +msgstr "S" + +msgid "Save" +msgstr "Speichern" + +msgid "Save this game" +msgstr "Mission speichern" + +msgid "Scenery choice" +msgstr "" +"Auswahl der\n" +"Umgebung" + +msgid "" +"Scroll speed\n" +"with mouse" +msgstr "" +"Geschwindigkeit\n" +"der Bildschirm-\n" +"verschiebungen\n" +"mit der Maus" + +msgid "" +"Select the\n" +"window mode" +msgstr "" +"Fenstermodus\n" +"auswählen" + +msgid "Settings" +msgstr "Einstellungen" + +msgid "Show videos" +msgstr "Zeigt die Videosequenzen" + +msgid "Sick Blupi" +msgstr "Kranker Blupi" + +msgid "Skill level" +msgstr "Schwierigkeitsgrad" + +msgid "Slower" +msgstr "Langsamer" + +msgid "" +"Sound effect\n" +"volume" +msgstr "" +"Lautstärke der\n" +"Geräuscheffekte" + +msgid "Special pavings" +msgstr "Spezialplatten" + +msgid "Spider" +msgstr "Spinne" + +msgid "Starting fire" +msgstr "Feuer" + +msgid "Sterile ground" +msgstr "Karger Untergrund" + +msgid "Sticky trap" +msgstr "Klebefalle" + +msgid "Stones" +msgstr "Steine" + +msgid "Stop" +msgstr "Halt" + +msgid "Striped paving stones" +msgstr "Gestreifte Quadrate" + +msgid "Take" +msgstr "Nehmen" + +# Beamgerät +msgid "Teleporter" +msgstr "Beammaschine" + +msgid "" +"This game is an original creation of Epsitec SA, CH-1400 Yverdon-les-Bains" +msgstr "" +"Dieses Spiel wurde ursprünglich durch Epsitec SA, CH-1400 Yverdon-les-Bains " +"entwickelt" + +msgid "This game uses statically linked free and open-source libraries:" +msgstr "" + +msgid "Time bomb" +msgstr "Zeitbombe" + +msgid "Tired Blupi" +msgstr "Erschöpfter Blupi" + +msgid "Tomatoes" +msgstr "Tomaten" + +msgid "Tomatoes on striped paving stones" +msgstr "Tomaten auf gestreiften Quadraten" + +msgid "Too close to water" +msgstr "Zu nahe am Wasser" + +msgid "Training" +msgstr "Training" + +msgid "Training number" +msgstr "Training Nummer" + +msgid "Transform" +msgstr "Verarbeiten" + +msgid "Transport" +msgstr "Transportmittel" + +msgid "Trapped enemy" +msgstr "Verklebter Feind" + +msgid "Tree" +msgstr "Bäume" + +msgid "Tree trunks" +msgstr "Baumstämme" + +msgid "Use Midi music (original)" +msgstr "" + +msgid "Use Ogg music" +msgstr "" + +msgid "Version" +msgstr "Version" + +msgid "Very good, success on all missions !" +msgstr "Bravo, das Spiel ist beendet !" + +msgid "Very good." +msgstr "Sehr gut" + +msgid "" +"Video\n" +"sequences" +msgstr "Videosequenzen" + +msgid "Virus" +msgstr "Virus" + +msgid "W" +msgstr "W" + +msgid "Wall" +msgstr "Mauer" + +msgid "Wall or palisade" +msgstr "Mauer oder Palissade" + +msgid "Water" +msgstr "Wasser" + +msgid "We hope you have had as much fun playing the game as we had making it !" +msgstr "" +"Hoffentlich hatten Sie genau soviel Spass beim Spielen wie wir beim " +"herstellen des Spiels !" + +msgid "Weapons" +msgstr "Waffen" + +msgid "Well done !" +msgstr "Toll, Du hast es geschafft" + +msgid "Windowed" +msgstr "Fenster" + +msgid "Work done" +msgstr "Arbeitsfortschritt" + +msgid "Workshop" +msgstr "Werkstatt" + +msgid "Yes" +msgstr "Ja" + +msgid "Yes, great ..." +msgstr "Ja, super" + +msgid "You have failed, try again..." +msgstr "Das war nichts, probier es noch einmal !" + +msgid "You have played Planet Blupi." +msgstr "Sie haben soeben mit Planet Blupi gespielt." + +#, c-format +msgid "construction %d, time %d" +msgstr "Konstruktion %d, Zeit %d" + +msgid "en" +msgstr "de" + +msgid "free slot" +msgstr "frei" + +msgid "http://www.blupi.org info@blupi.org" +msgstr "http://www.blupi.org info@blupi.org" + +#, c-format +msgid "mission %d, time %d" +msgstr "Mission %d, Zeit %d" + +#, c-format +msgid "training %d, time %d" +msgstr "Training %d, Zeit %d" + +#, fuzzy +#~ msgid "Nearest" +#~ msgstr "Wald" + +#~ msgid "Quit BLUPI" +#~ msgstr "BLUPI beenden" diff --git a/resources/po/en_US.po b/resources/po/en_US.po new file mode 100644 index 0000000..8d5f9f6 --- /dev/null +++ b/resources/po/en_US.po @@ -0,0 +1,910 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-08-08 07:29+0200\n" +"PO-Revision-Date: 2017-02-27 21:28+0100\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: en_US\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.8.11\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid " - FFmpeg (LGPLv2.1)" +msgstr "" + +msgid " - GNU/gettext and GNU/libiconv (GPLv3)" +msgstr "" + +msgid " - SDL2, SDL2_image and SDL2_mixer (zlib license)" +msgstr "" + +msgid " - SDL_kitchensink (MIT)" +msgstr "" + +msgid " - argagg (MIT)" +msgstr "" + +msgid " - libasound (LGPLv2.1)" +msgstr "" + +msgid " - libcurl (MIT/X derivate)" +msgstr "" + +msgid " - libogg and libvorbis (own license)" +msgstr "" + +msgid " - libpng (own license)" +msgstr "" + +msgid " - libpulse (LGPLv2.1)" +msgstr "" + +msgid " - libsndfile (LGPLv3)" +msgstr "" + +msgid " - zlib (own license)" +msgstr "" + +msgid "(isolated tower)" +msgstr "" + +msgid "" +"1: Cut down a tree \n" +"2: Build a bridge" +msgstr "" + +msgid "" +"1: Cut down a tree \n" +"2: Make a boat" +msgstr "" + +msgid "" +"1: Cut down a tree \n" +"2: Make a palisade" +msgstr "" + +msgid "" +"1: Extract iron\n" +"2: Make a Jeep" +msgstr "" + +msgid "" +"1: Extract iron\n" +"2: Make a bomb" +msgstr "" + +msgid "" +"1: Extract iron\n" +"2: Make an armour" +msgstr "" + +msgid "" +"1: Grow tomatoes\n" +"2: Eat" +msgstr "" + +msgid "" +"1: Make a bunch\n" +"2: Transform" +msgstr "" + +msgid "" +"1: Take\n" +"2: Build a bridge" +msgstr "" + +msgid "" +"1: Take\n" +"2: Build palisade" +msgstr "" + +msgid "" +"1: Take\n" +"2: Make a boat" +msgstr "" + +msgid "" +"1: Take\n" +"2: Transform" +msgstr "" + +msgid "" +"1|Drop planks on striped \n" +"1|paving stones." +msgstr "" + +msgid "" +"1|Drop platinium on striped \n" +"1|paving stones." +msgstr "" + +msgid "" +"1|Drop tomatoes on striped \n" +"1|paving stones." +msgstr "" + +msgid "" +"1|Each Blupi in\n" +"1|his house." +msgstr "" + +msgid "" +"1|Go on striped\n" +"1|paving stones." +msgstr "" + +msgid "1|Goal :" +msgstr "" + +msgid "" +"1|Kill all\n" +"1|enemies !" +msgstr "" + +msgid "" +"1|Resist until\n" +"1|fire extinction ..." +msgstr "" + +#, c-format +msgid "" +"1|The Blupi population must\n" +"1|be of at least %d Blupi." +msgstr "" + +msgid "" +"1|The robot must reach\n" +"1|the striped paving stones." +msgstr "" + +msgid "Aliasing" +msgstr "" + +msgid "All licenses are available under share/doc/planetblupi/copyright" +msgstr "" + +msgid "Already two teleporters" +msgstr "" + +msgid "Another mistake..." +msgstr "" + +msgid "Anti-aliasing" +msgstr "" + +msgid "Armour" +msgstr "" + +msgid "Available buttons" +msgstr "" + +msgid "Bang, failed again !" +msgstr "" + +msgid "Bank" +msgstr "" + +msgid "Blow up" +msgstr "" + +msgid "Blupi" +msgstr "" + +msgid "Blupi in house" +msgstr "" + +msgid "Blupi on striped paving stones" +msgstr "" + +msgid "Blupi's energy" +msgstr "" + +msgid "Blupi's house" +msgstr "" + +msgid "Boat" +msgstr "" + +msgid "Bouncing bomb" +msgstr "" + +msgid "Bridge" +msgstr "" + +msgid "Bridge finished" +msgstr "" + +msgid "Buildings" +msgstr "" + +msgid "Bulldozer" +msgstr "" + +msgid "Bunch of flowers" +msgstr "" + +msgid "Burnt ground" +msgstr "" + +msgid "Cancel last operation" +msgstr "" + +msgid "Carve a rock" +msgstr "" + +msgid "Carve rocks" +msgstr "" + +msgid "" +"Change the\n" +"display mode" +msgstr "" + +msgid "" +"Change the\n" +"render quality" +msgstr "" + +msgid "" +"Change the\n" +"window size" +msgstr "" + +msgid "" +"Choose the\n" +"music format" +msgstr "" + +msgid "Construct this game" +msgstr "" + +msgid "Construction" +msgstr "" + +msgid "Construction number" +msgstr "" + +msgid "Continue this game" +msgstr "" + +msgid "Cut down a tree" +msgstr "" + +msgid "Cut down trees" +msgstr "" + +msgid "Decorative plants" +msgstr "" + +msgid "Delete figure" +msgstr "" + +msgid "Delete fire" +msgstr "" + +msgid "Delete item" +msgstr "" + +msgid "Demo" +msgstr "" + +msgid "Desert" +msgstr "" + +msgid "Desktop" +msgstr "" + +msgid "Desktop mode" +msgstr "" + +msgid "Difficult" +msgstr "" + +msgid "Disable anti-aliasing" +msgstr "" + +msgid "Drink" +msgstr "" + +msgid "Drop" +msgstr "" + +msgid "Dynamite" +msgstr "" + +msgid "E" +msgstr "" + +msgid "Easy" +msgstr "" + +msgid "Eat" +msgstr "" + +msgid "Eggs" +msgstr "" + +msgid "Electrocutor" +msgstr "" + +msgid "Enable anti-aliasing" +msgstr "" + +msgid "Ending conditions" +msgstr "" + +msgid "Enemy barrier" +msgstr "" + +msgid "Enemy buildings" +msgstr "" + +msgid "Enemy construction" +msgstr "" + +msgid "Enemy ground" +msgstr "" + +msgid "Enemy rocket" +msgstr "" + +msgid "Excellent..." +msgstr "" + +msgid "Extract iron" +msgstr "" + +msgid "Faster" +msgstr "" + +msgid "Finish" +msgstr "" + +msgid "Fire" +msgstr "" + +msgid "Fire out" +msgstr "" + +msgid "Flag" +msgstr "" + +msgid "Flowers" +msgstr "" + +msgid "Forest" +msgstr "" + +msgid "Forest under snow" +msgstr "" + +msgid "Fullscreen" +msgstr "" + +msgid "Game paused" +msgstr "" + +msgid "Garden shed" +msgstr "" + +msgid "" +"Global game\n" +"speed" +msgstr "" + +msgid "Global settings" +msgstr "" + +msgid "Go" +msgstr "" + +msgid "Grow tomatoes" +msgstr "" + +msgid "Help" +msgstr "" + +msgid "Help number" +msgstr "" + +msgid "Helper robot" +msgstr "" + +msgid "Ice" +msgstr "" + +msgid "Impossible" +msgstr "" + +#, c-format +msgid "Impossible to win if less than %d Blupi" +msgstr "" + +msgid "Inadequate ground" +msgstr "" + +msgid "Increase volume" +msgstr "" + +msgid "Increase window size" +msgstr "" + +msgid "Incubator" +msgstr "" + +msgid "Incubator or teleporter" +msgstr "" + +msgid "Inflammable ground" +msgstr "" + +msgid "Insert CD-Rom Planet Blupi and wait a few seconds..." +msgstr "" + +msgid "" +"Interface language\n" +"and sounds" +msgstr "" + +msgid "Interrupt" +msgstr "" + +msgid "Iron" +msgstr "" + +msgid "Items" +msgstr "" + +msgid "Jeep" +msgstr "" + +msgid "Laboratory" +msgstr "" + +msgid "Last construction resolved !" +msgstr "" + +msgid "Leave Jeep" +msgstr "" + +msgid "Legacy" +msgstr "" + +msgid "Legacy mode (640x480)" +msgstr "" + +#, c-format +msgid "Lost if less than %d Blupi" +msgstr "" + +msgid "Make a Jeep" +msgstr "" + +msgid "Make a helper robot" +msgstr "" + +msgid "Make a time bomb" +msgstr "" + +msgid "Make armour" +msgstr "" + +msgid "Make bunch of flowers" +msgstr "" + +msgid "Make bunches of flowers" +msgstr "" + +msgid "Master robot" +msgstr "" + +msgid "Medical potion" +msgstr "" + +msgid "Midi" +msgstr "" + +msgid "Mine" +msgstr "" + +msgid "Miscellaneous ground" +msgstr "" + +msgid "Mission number" +msgstr "" + +msgid "Mission over..." +msgstr "" + +msgid "Missions" +msgstr "" + +msgid "" +"Music\n" +"volume" +msgstr "" + +msgid "Music choice" +msgstr "" + +msgid "Music number 1" +msgstr "" + +msgid "Music number 10" +msgstr "" + +msgid "Music number 2" +msgstr "" + +msgid "Music number 3" +msgstr "" + +msgid "Music number 4" +msgstr "" + +msgid "Music number 5" +msgstr "" + +msgid "Music number 6" +msgstr "" + +msgid "Music number 7" +msgstr "" + +msgid "Music number 8" +msgstr "" + +msgid "Music number 9" +msgstr "" + +msgid "N" +msgstr "" + +#, c-format +msgid "New version available for download on www.blupi.org (v%s)" +msgstr "" + +msgid "Next game" +msgstr "" + +msgid "Next language" +msgstr "" + +msgid "Next page" +msgstr "" + +msgid "No" +msgstr "" + +msgid "No more enemies" +msgstr "" + +msgid "No music" +msgstr "" + +msgid "No video" +msgstr "" + +msgid "No, not that way !" +msgstr "" + +msgid "No, wrong way ..." +msgstr "" + +msgid "None" +msgstr "" + +msgid "Normal ground" +msgstr "" + +msgid "Not available" +msgstr "" + +msgid "Not enough energy" +msgstr "" + +msgid "Now go on mission." +msgstr "" + +msgid "Occupied ground" +msgstr "" + +msgid "Ogg" +msgstr "" + +msgid "Open another game" +msgstr "" + +msgid "Opposite bank no good" +msgstr "" + +msgid "Palisade" +msgstr "" + +msgid "Paving stones" +msgstr "" + +msgid "Planet Blupi" +msgstr "" + +msgid "Planet Blupi -- stop" +msgstr "" + +msgid "Planks" +msgstr "" + +msgid "Planks on striped paving stones" +msgstr "" + +msgid "Platinium" +msgstr "" + +msgid "Platinium on striped paving stones" +msgstr "" + +msgid "Play this game" +msgstr "" + +msgid "Poison" +msgstr "" + +msgid "Prairie" +msgstr "" + +msgid "Previous game" +msgstr "" + +msgid "Previous language" +msgstr "" + +msgid "Previous page" +msgstr "" + +msgid "Prospect for iron" +msgstr "" + +msgid "Protection tower" +msgstr "" + +msgid "Quit" +msgstr "" + +msgid "Quit Planet Blupi" +msgstr "" + +msgid "Quit construction" +msgstr "" + +msgid "Quit this game" +msgstr "" + +msgid "REC" +msgstr "" + +msgid "Reduce volume" +msgstr "" + +msgid "Reduce window size" +msgstr "" + +msgid "Repeat" +msgstr "" + +msgid "Restart this game" +msgstr "" + +msgid "Robot on striped paving stones" +msgstr "" + +msgid "Rocks" +msgstr "" + +msgid "S" +msgstr "" + +msgid "Save" +msgstr "" + +msgid "Save this game" +msgstr "" + +msgid "Scenery choice" +msgstr "" + +msgid "" +"Scroll speed\n" +"with mouse" +msgstr "" + +msgid "" +"Select the\n" +"window mode" +msgstr "" + +msgid "Settings" +msgstr "" + +msgid "Show videos" +msgstr "" + +msgid "Sick Blupi" +msgstr "" + +msgid "Skill level" +msgstr "" + +msgid "Slower" +msgstr "" + +msgid "" +"Sound effect\n" +"volume" +msgstr "" + +msgid "Special pavings" +msgstr "" + +msgid "Spider" +msgstr "" + +msgid "Starting fire" +msgstr "" + +msgid "Sterile ground" +msgstr "" + +msgid "Sticky trap" +msgstr "" + +msgid "Stones" +msgstr "" + +msgid "Stop" +msgstr "" + +msgid "Striped paving stones" +msgstr "" + +msgid "Take" +msgstr "" + +msgid "Teleporter" +msgstr "" + +msgid "" +"This game is an original creation of Epsitec SA, CH-1400 Yverdon-les-Bains" +msgstr "" + +msgid "This game uses statically linked free and open-source libraries:" +msgstr "" + +msgid "Time bomb" +msgstr "" + +msgid "Tired Blupi" +msgstr "" + +msgid "Tomatoes" +msgstr "" + +msgid "Tomatoes on striped paving stones" +msgstr "" + +msgid "Too close to water" +msgstr "" + +msgid "Training" +msgstr "" + +msgid "Training number" +msgstr "" + +msgid "Transform" +msgstr "" + +msgid "Transport" +msgstr "" + +msgid "Trapped enemy" +msgstr "" + +msgid "Tree" +msgstr "" + +msgid "Tree trunks" +msgstr "" + +msgid "Use Midi music (original)" +msgstr "" + +msgid "Use Ogg music" +msgstr "" + +msgid "Version" +msgstr "" + +msgid "Very good, success on all missions !" +msgstr "" + +msgid "Very good." +msgstr "" + +msgid "" +"Video\n" +"sequences" +msgstr "" + +msgid "Virus" +msgstr "" + +msgid "W" +msgstr "" + +msgid "Wall" +msgstr "" + +msgid "Wall or palisade" +msgstr "" + +msgid "Water" +msgstr "" + +msgid "We hope you have had as much fun playing the game as we had making it !" +msgstr "" + +msgid "Weapons" +msgstr "" + +msgid "Well done !" +msgstr "" + +msgid "Windowed" +msgstr "" + +msgid "Work done" +msgstr "" + +msgid "Workshop" +msgstr "" + +msgid "Yes" +msgstr "" + +msgid "Yes, great ..." +msgstr "" + +msgid "You have failed, try again..." +msgstr "" + +msgid "You have played Planet Blupi." +msgstr "" + +#, c-format +msgid "construction %d, time %d" +msgstr "" + +msgid "en" +msgstr "en_US" + +msgid "free slot" +msgstr "" + +msgid "http://www.blupi.org info@blupi.org" +msgstr "" + +#, c-format +msgid "mission %d, time %d" +msgstr "" + +#, c-format +msgid "training %d, time %d" +msgstr "" diff --git a/resources/po/fr.po b/resources/po/fr.po new file mode 100644 index 0000000..fcb9835 --- /dev/null +++ b/resources/po/fr.po @@ -0,0 +1,1018 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Mathieu Schroeter , 2017. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-08-08 07:29+0200\n" +"PO-Revision-Date: 2019-02-17 23:21+0100\n" +"Last-Translator: Mathieu Schroeter \n" +"Language-Team: French \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.2.1\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +msgid " - FFmpeg (LGPLv2.1)" +msgstr " - FFmpeg (LGPLv2.1)" + +msgid " - GNU/gettext and GNU/libiconv (GPLv3)" +msgstr " - GNU/gettext et GNU/libiconv (GPLv3)" + +msgid " - SDL2, SDL2_image and SDL2_mixer (zlib license)" +msgstr " - SDL2, SDL2_image et SDL2_mixer (licence zlib)" + +msgid " - SDL_kitchensink (MIT)" +msgstr " - SDL_kitchensink (MIT)" + +msgid " - argagg (MIT)" +msgstr " - argagg (MIT)" + +msgid " - libasound (LGPLv2.1)" +msgstr " - libasound (LGPLv2.1)" + +msgid " - libcurl (MIT/X derivate)" +msgstr " - libcurl (dérivée de MIT/X)" + +msgid " - libogg and libvorbis (own license)" +msgstr " - libogg and libvorbis (propre licence)" + +msgid " - libpng (own license)" +msgstr " - libpng (propre licence)" + +msgid " - libpulse (LGPLv2.1)" +msgstr " - libpulse (LGPLv2.1)" + +msgid " - libsndfile (LGPLv3)" +msgstr " - libsndfile (LGPLv3)" + +msgid " - zlib (own license)" +msgstr " - zlib (propre licence)" + +msgid "(isolated tower)" +msgstr "(tour isolée)" + +msgid "" +"1: Cut down a tree \n" +"2: Build a bridge" +msgstr "" +"1: Abat un arbre\n" +"2: Construit pont" + +msgid "" +"1: Cut down a tree \n" +"2: Make a boat" +msgstr "" +"1: Abat un arbre\n" +"2: Construit bateau" + +msgid "" +"1: Cut down a tree \n" +"2: Make a palisade" +msgstr "" +"1: Abat un arbre\n" +"2: Construit palissade" + +msgid "" +"1: Extract iron\n" +"2: Make a Jeep" +msgstr "" +"1: Extrait du fer\n" +"2: Fabrique jeep" + +msgid "" +"1: Extract iron\n" +"2: Make a bomb" +msgstr "" +"1: Extrait du fer\n" +"2: Fabrique bombe" + +msgid "" +"1: Extract iron\n" +"2: Make an armour" +msgstr "" +"1: Extrait du fer\n" +"2: Fabrique armure" + +msgid "" +"1: Grow tomatoes\n" +"2: Eat" +msgstr "" +"1: Cultive ...\n" +"2: Mange" + +msgid "" +"1: Make a bunch\n" +"2: Transform" +msgstr "" +"1: Fait un bouquet\n" +"2: Transforme" + +msgid "" +"1: Take\n" +"2: Build a bridge" +msgstr "" +"1: Prend\n" +"2: Construit pont" + +msgid "" +"1: Take\n" +"2: Build palisade" +msgstr "" +"1: Prend\n" +"2: Construit palissade" + +msgid "" +"1: Take\n" +"2: Make a boat" +msgstr "" +"1: Prend\n" +"2: Construit bateau" + +msgid "" +"1: Take\n" +"2: Transform" +msgstr "" +"1: Prend\n" +"2: Transforme" + +msgid "" +"1|Drop planks on striped \n" +"1|paving stones." +msgstr "" +"1|Déposer des planches\n" +"1|sur les dalles hachurées." + +msgid "" +"1|Drop platinium on striped \n" +"1|paving stones." +msgstr "" +"1|Déposer du platinium\n" +"1|sur les dalles hachurées." + +msgid "" +"1|Drop tomatoes on striped \n" +"1|paving stones." +msgstr "" +"1|Déposer des tomates\n" +"1|sur les dalles hachurées." + +msgid "" +"1|Each Blupi in\n" +"1|his house." +msgstr "" +"1|Chaque Blupi dans\n" +"1|sa maison." + +msgid "" +"1|Go on striped\n" +"1|paving stones." +msgstr "" +"1|Aller sur les dalles\n" +"1|hachurées." + +msgid "1|Goal :" +msgstr "1|Objectif :" + +msgid "" +"1|Kill all\n" +"1|enemies !" +msgstr "" +"1|Supprimer tous les\n" +"1|ennemis !" + +msgid "" +"1|Resist until\n" +"1|fire extinction ..." +msgstr "" +"1|Résister jusqu'à\n" +"1|l'extinction du feu ..." + +#, c-format +msgid "" +"1|The Blupi population must\n" +"1|be of at least %d Blupi." +msgstr "" +"1|La population doit être\n" +"1|d'au moins %d Blupi." + +msgid "" +"1|The robot must reach\n" +"1|the striped paving stones." +msgstr "" +"1|Le robot doit atteindre\n" +"1|les dalles hachurées." + +msgid "Aliasing" +msgstr "Crénelage" + +msgid "All licenses are available under share/doc/planetblupi/copyright" +msgstr "" +"Toutes les licences sont disponibles sous share/doc/planetblupi/copyright" + +msgid "Already two teleporters" +msgstr "Déjà 2 téléporteurs" + +msgid "Another mistake..." +msgstr "Caramba, encore raté ..." + +msgid "Anti-aliasing" +msgstr "Anticrénelage" + +msgid "Armour" +msgstr "Armure" + +msgid "Available buttons" +msgstr "Boutons disponibles" + +msgid "Bang, failed again !" +msgstr "Paf, c'est raté !" + +msgid "Bank" +msgstr "Rive" + +msgid "Blow up" +msgstr "Explose" + +msgid "Blupi" +msgstr "Blupi" + +msgid "Blupi in house" +msgstr "Blupi dans sa maison" + +msgid "Blupi on striped paving stones" +msgstr "Blupi sur dalles hachurées" + +msgid "Blupi's energy" +msgstr "Energie de Blupi" + +msgid "Blupi's house" +msgstr "Maison de blupi" + +msgid "Boat" +msgstr "Bateau" + +msgid "Bouncing bomb" +msgstr "Bombe sauteuse" + +msgid "Bridge" +msgstr "Pont" + +msgid "Bridge finished" +msgstr "Pont terminé" + +msgid "Buildings" +msgstr "Bâtiments" + +msgid "Bulldozer" +msgstr "Bulldozer" + +msgid "Bunch of flowers" +msgstr "Bouquet de fleurs" + +msgid "Burnt ground" +msgstr "Mousse brûlée" + +msgid "Cancel last operation" +msgstr "Annuler la dernière opération" + +msgid "Carve a rock" +msgstr "Taille un rocher" + +msgid "Carve rocks" +msgstr "Taille des rochers" + +msgid "" +"Change the\n" +"display mode" +msgstr "" +"Modifie le mode\n" +"d'affichage" + +msgid "" +"Change the\n" +"render quality" +msgstr "" +"Modifie la\n" +"qualité de rendu" + +msgid "" +"Change the\n" +"window size" +msgstr "" +"Modifie la taille\n" +"de la fenêtre" + +msgid "" +"Choose the\n" +"music format" +msgstr "" +"Choisi le\n" +"format de\n" +"la musique" + +msgid "Construct this game" +msgstr "Construire cette partie" + +msgid "Construction" +msgstr "Construction" + +msgid "Construction number" +msgstr "Construction numéro" + +msgid "Continue this game" +msgstr "Continuer la partie" + +msgid "Cut down a tree" +msgstr "Abat un arbre" + +msgid "Cut down trees" +msgstr "Abat des arbres" + +msgid "Decorative plants" +msgstr "Plantes ornementales" + +msgid "Delete figure" +msgstr "Supprime personnage" + +msgid "Delete fire" +msgstr "Supprime feu" + +msgid "Delete item" +msgstr "Supprime objet" + +msgid "Demo" +msgstr "Démo" + +msgid "Desert" +msgstr "Désert" + +msgid "Desktop" +msgstr "Bureau" + +msgid "Desktop mode" +msgstr "Mode bureau" + +msgid "Difficult" +msgstr "Difficile" + +msgid "Disable anti-aliasing" +msgstr "Désactive l'anticrénelage" + +msgid "Drink" +msgstr "Boit" + +msgid "Drop" +msgstr "Dépose" + +msgid "Dynamite" +msgstr "Dynamite" + +msgid "E" +msgstr "E" + +msgid "Easy" +msgstr "Facile" + +msgid "Eat" +msgstr "Mange" + +msgid "Eggs" +msgstr "Oeufs" + +msgid "Electrocutor" +msgstr "Electrocuteur" + +msgid "Enable anti-aliasing" +msgstr "Active l'anticrénelage" + +msgid "Ending conditions" +msgstr "Conditions de fin" + +msgid "Enemy barrier" +msgstr "Barrière ennemie" + +msgid "Enemy buildings" +msgstr "Bâtiments ennemis" + +msgid "Enemy construction" +msgstr "Construction ennemie" + +msgid "Enemy ground" +msgstr "Sol ennemi" + +msgid "Enemy rocket" +msgstr "Fusée ennemie" + +msgid "Excellent..." +msgstr "Magnifique, excellent ..." + +msgid "Extract iron" +msgstr "Extrait du fer" + +msgid "Faster" +msgstr "Augmente la vitesse" + +msgid "Finish" +msgstr "Terminer" + +msgid "Fire" +msgstr "Feu" + +msgid "Fire out" +msgstr "Feu stoppé" + +msgid "Flag" +msgstr "Drapeau" + +msgid "Flowers" +msgstr "Fleurs" + +msgid "Forest" +msgstr "Forêt" + +msgid "Forest under snow" +msgstr "Forêt enneigée" + +msgid "Fullscreen" +msgstr "Plein écran" + +msgid "Game paused" +msgstr "Partie interrompue" + +msgid "Garden shed" +msgstr "Cabane de jardin" + +msgid "" +"Global game\n" +"speed" +msgstr "" +"Vitesse globale\n" +"du jeu" + +msgid "Global settings" +msgstr "Réglages généraux" + +msgid "Go" +msgstr "Va" + +msgid "Grow tomatoes" +msgstr "Cultive un jardin" + +msgid "Help" +msgstr "Aide" + +msgid "Help number" +msgstr "Aide numéro" + +msgid "Helper robot" +msgstr "Robot-aide" + +msgid "Ice" +msgstr "Glace" + +msgid "Impossible" +msgstr "Impossible ici" + +#, c-format +msgid "Impossible to win if less than %d Blupi" +msgstr "Impossible de gagner si moins de %d Blupi" + +msgid "Inadequate ground" +msgstr "Terrain pas adapté" + +msgid "Increase volume" +msgstr "Augmente le volume" + +msgid "Increase window size" +msgstr "Augmente la taille de la fenêtre" + +msgid "Incubator" +msgstr "Couveuse" + +msgid "Incubator or teleporter" +msgstr "Couveuse ou téléporteur" + +msgid "Inflammable ground" +msgstr "Sol inflammable" + +msgid "Insert CD-Rom Planet Blupi and wait a few seconds..." +msgstr "" +"Veuillez insérer le CD-Rom Planet Blupi, puis attendre quelques secondes ..." + +msgid "" +"Interface language\n" +"and sounds" +msgstr "" +"Langue de\n" +"l'interface et\n" +"des bruitages" + +msgid "Interrupt" +msgstr "Interrompre" + +msgid "Iron" +msgstr "Minerai de fer" + +msgid "Items" +msgstr "Objets" + +msgid "Jeep" +msgstr "Jeep" + +msgid "Laboratory" +msgstr "Laboratoire" + +msgid "Last construction resolved !" +msgstr "Dernière construction résolue !" + +msgid "Leave Jeep" +msgstr "Descend" + +msgid "Legacy" +msgstr "Ancien" + +msgid "Legacy mode (640x480)" +msgstr "Ancien mode (640x480)" + +#, c-format +msgid "Lost if less than %d Blupi" +msgstr "Perdu si moins de %d Blupi" + +msgid "Make a Jeep" +msgstr "Farbique une jeep" + +msgid "Make a helper robot" +msgstr "Fabrique un robot" + +msgid "Make a time bomb" +msgstr "Fabrique une bombe" + +msgid "Make armour" +msgstr "Fabrique une armure" + +msgid "Make bunch of flowers" +msgstr "Fait un bouquet" + +msgid "Make bunches of flowers" +msgstr "Fait des bouquets" + +msgid "Master robot" +msgstr "Robot-maître" + +msgid "Medical potion" +msgstr "Potion" + +msgid "Midi" +msgstr "Midi" + +msgid "Mine" +msgstr "Mine de fer" + +msgid "Miscellaneous ground" +msgstr "Sol mixte" + +msgid "Mission number" +msgstr "Mission numéro" + +msgid "Mission over..." +msgstr "Mission accomplie..." + +msgid "Missions" +msgstr "Missions" + +msgid "" +"Music\n" +"volume" +msgstr "" +"Volume\n" +"des musiques" + +msgid "Music choice" +msgstr "Choix de la musique" + +msgid "Music number 1" +msgstr "Musique numéro 1" + +msgid "Music number 10" +msgstr "Musique numéro 10" + +msgid "Music number 2" +msgstr "Musique numéro 2" + +msgid "Music number 3" +msgstr "Musique numéro 3" + +msgid "Music number 4" +msgstr "Musique numéro 4" + +msgid "Music number 5" +msgstr "Musique numéro 5" + +msgid "Music number 6" +msgstr "Musique numéro 6" + +msgid "Music number 7" +msgstr "Musique numéro 7" + +msgid "Music number 8" +msgstr "Musique numéro 8" + +msgid "Music number 9" +msgstr "Musique numéro 9" + +msgid "N" +msgstr "N" + +#, c-format +msgid "New version available for download on www.blupi.org (v%s)" +msgstr "Nouvelle version disponible au téléchargement sur www.blupi.org (v%s)" + +msgid "Next game" +msgstr "Partie suivante" + +msgid "Next language" +msgstr "Langue suivante" + +msgid "Next page" +msgstr "Page suivante" + +msgid "No" +msgstr "Non" + +msgid "No more enemies" +msgstr "Plus d'ennemis" + +msgid "No music" +msgstr "Pas de musique" + +msgid "No video" +msgstr "Pas de vidéo" + +msgid "No, not that way !" +msgstr "Mais non, pas comme ça !" + +msgid "No, wrong way ..." +msgstr "Et non, ce n'est pas ça ..." + +msgid "None" +msgstr "Aucun" + +msgid "Normal ground" +msgstr "Sol normal" + +msgid "Not available" +msgstr "Non disponible" + +msgid "Not enough energy" +msgstr "Pas assez d'énergie" + +msgid "Now go on mission." +msgstr "Passe maintenant aux missions." + +msgid "Occupied ground" +msgstr "Terrain occupé" + +msgid "Ogg" +msgstr "Ogg" + +msgid "Open another game" +msgstr "Ouvrir une autre partie" + +msgid "Opposite bank no good" +msgstr "Autre rive pas ok" + +msgid "Palisade" +msgstr "Palissade" + +msgid "Paving stones" +msgstr "Dalles" + +msgid "Planet Blupi" +msgstr "Planet Blupi" + +msgid "Planet Blupi -- stop" +msgstr "Planet Blupi -- arrêt" + +msgid "Planks" +msgstr "Planches" + +msgid "Planks on striped paving stones" +msgstr "Planches sur dalles hachurées" + +msgid "Platinium" +msgstr "Platinium" + +msgid "Platinium on striped paving stones" +msgstr "Platinium sur dalles hachurées" + +msgid "Play this game" +msgstr "Jouer cette partie" + +msgid "Poison" +msgstr "Poison" + +msgid "Prairie" +msgstr "Prairie" + +msgid "Previous game" +msgstr "Partie précédente" + +msgid "Previous language" +msgstr "Langue précédente" + +msgid "Previous page" +msgstr "Page précédente" + +msgid "Prospect for iron" +msgstr "Cherche du fer" + +msgid "Protection tower" +msgstr "Tour de protection" + +msgid "Quit" +msgstr "Quitte" + +msgid "Quit Planet Blupi" +msgstr "Quitter Planet Blupi" + +msgid "Quit construction" +msgstr "Terminer la construction" + +msgid "Quit this game" +msgstr "Abandonner la partie" + +msgid "REC" +msgstr "REC" + +msgid "Reduce volume" +msgstr "Diminue le volume" + +msgid "Reduce window size" +msgstr "Réduire la taille de la fenêtre" + +msgid "Repeat" +msgstr "Répète" + +msgid "Restart this game" +msgstr "Recommencer" + +msgid "Robot on striped paving stones" +msgstr "Robot sur dalles hachurées" + +msgid "Rocks" +msgstr "Rochers" + +msgid "S" +msgstr "S" + +msgid "Save" +msgstr "Enregistrer" + +msgid "Save this game" +msgstr "Enregistrer la partie en cours" + +msgid "Scenery choice" +msgstr "Choix des décors" + +msgid "" +"Scroll speed\n" +"with mouse" +msgstr "" +"Vitesse\n" +"des décalages\n" +"avec la souris" + +msgid "" +"Select the\n" +"window mode" +msgstr "" +"Sélectionne le\n" +"mode de fenêtre" + +msgid "Settings" +msgstr "Réglages" + +msgid "Show videos" +msgstr "Montre les vidéos" + +msgid "Sick Blupi" +msgstr "Blupi malade" + +msgid "Skill level" +msgstr "Niveau de difficulté" + +msgid "Slower" +msgstr "Diminue la vitesse" + +msgid "" +"Sound effect\n" +"volume" +msgstr "" +"Volume\n" +"des bruitages" + +msgid "Special pavings" +msgstr "Dalles spéciales" + +msgid "Spider" +msgstr "Araignée" + +msgid "Starting fire" +msgstr "Début d'incendie" + +msgid "Sterile ground" +msgstr "Sol improductif" + +msgid "Sticky trap" +msgstr "Piège à glu" + +msgid "Stones" +msgstr "Pierres" + +msgid "Stop" +msgstr "Stoppe" + +msgid "Striped paving stones" +msgstr "Dalles hachurées" + +msgid "Take" +msgstr "Prend" + +msgid "Teleporter" +msgstr "Téléporteur" + +msgid "" +"This game is an original creation of Epsitec SA, CH-1400 Yverdon-les-Bains" +msgstr "" +"Ce jeu est une création originale d'Epsitec SA, CH-1400 Yverdon-les-Bains" + +msgid "This game uses statically linked free and open-source libraries:" +msgstr "Ce jeu utilise des bibliothèques libres et open-sources :" + +msgid "Time bomb" +msgstr "Bombe à retardement" + +msgid "Tired Blupi" +msgstr "Blupi fatigué" + +msgid "Tomatoes" +msgstr "Tomates" + +msgid "Tomatoes on striped paving stones" +msgstr "Tomates sur dalles hachurées" + +msgid "Too close to water" +msgstr "Trop près de l'eau" + +msgid "Training" +msgstr "Entraînement" + +msgid "Training number" +msgstr "Entraînement numéro" + +msgid "Transform" +msgstr "Transforme" + +msgid "Transport" +msgstr "Moyens de transport" + +msgid "Trapped enemy" +msgstr "Ennemi piégé" + +msgid "Tree" +msgstr "Arbres" + +msgid "Tree trunks" +msgstr "Troncs" + +msgid "Use Midi music (original)" +msgstr "Utilise la musique Midi (originale)" + +msgid "Use Ogg music" +msgstr "Utilise la musique Ogg" + +msgid "Version" +msgstr "Version" + +msgid "Very good, success on all missions !" +msgstr "Magnifique, le jeu est terminé !" + +msgid "Very good." +msgstr "Très bien." + +msgid "" +"Video\n" +"sequences" +msgstr "" +"Séquences\n" +"vidéo" + +msgid "Virus" +msgstr "Virus" + +msgid "W" +msgstr "O" + +msgid "Wall" +msgstr "Mur anti-feu" + +msgid "Wall or palisade" +msgstr "Mur ou palissade" + +msgid "Water" +msgstr "Eau" + +msgid "We hope you have had as much fun playing the game as we had making it !" +msgstr "" +"Nous espérons que vous avez eu autant de plaisir à y jouer que nous à le " +"réaliser !" + +msgid "Weapons" +msgstr "Armes" + +msgid "Well done !" +msgstr "Bravo, c'est réussi !" + +msgid "Windowed" +msgstr "Fenêtré" + +msgid "Work done" +msgstr "Travail en cours" + +msgid "Workshop" +msgstr "Usine" + +msgid "Yes" +msgstr "Oui" + +msgid "Yes, great ..." +msgstr "Oui, super ..." + +msgid "You have failed, try again..." +msgstr "C'est raté, essaie encore une fois..." + +msgid "You have played Planet Blupi." +msgstr "Vous avez joué à Planet Blupi." + +#, c-format +msgid "construction %d, time %d" +msgstr "construction %d, temps %d" + +msgid "en" +msgstr "fr" + +msgid "free slot" +msgstr "libre" + +msgid "http://www.blupi.org info@blupi.org" +msgstr "http://www.blupi.org info@blupi.org" + +#, c-format +msgid "mission %d, time %d" +msgstr "mission %d, temps %d" + +#, c-format +msgid "training %d, time %d" +msgstr "entraînement %d, temps %d" + +#~ msgid "Best" +#~ msgstr "Meilleure" + +#~ msgctxt "Flower|2|" +#~ msgid "Bunch of flowers" +#~ msgstr "Bouquet de fleurs" + +#~ msgctxt "Flower|3|" +#~ msgid "Bunch of flowers" +#~ msgstr "Bouquet de fleurs" + +#~ msgid "Change for desktop mode" +#~ msgstr "Change pour le mode bureau" + +#~ msgctxt "Flower|2|" +#~ msgid "Flowers" +#~ msgstr "Fleurs" + +#~ msgctxt "Flower|3|" +#~ msgid "Flowers" +#~ msgstr "Fleurs" + +#~ msgid "N/A" +#~ msgstr "ND" + +#~ msgid "Nearest" +#~ msgstr "Au plus proche" + +#~ msgid "Quit BLUPI" +#~ msgstr "Quitter BLUPI" + +#~ msgid "Use the best render quality" +#~ msgstr "Utilise la meilleure qualité de rendu" + +#~ msgid "Use the nearest render quality" +#~ msgstr "Utilise la qualité de rendu au plus proche" diff --git a/resources/po/he.po b/resources/po/he.po new file mode 100644 index 0000000..9394348 --- /dev/null +++ b/resources/po/he.po @@ -0,0 +1,975 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-01-27 15:19+0100\n" +"PO-Revision-Date: 2019-02-17 14:11+0100\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: he\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.2.1\n" +"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : n==2 ? 1 : n>10 && n%10==0 ? " +"2 : 3);\n" + +msgid " - FFmpeg (LGPLv2.1)" +msgstr " - FFmpeg (LGPLv2.1)" + +msgid " - GNU/gettext and GNU/libiconv (GPLv3)" +msgstr " - GNU/gettext and GNU/libiconv (GPLv3)" + +msgid " - SDL2, SDL2_image and SDL2_mixer (zlib license)" +msgstr " - SDL2, SDL2_image and SDL2_mixer (zlib license)" + +msgid " - SDL_kitchensink (MIT)" +msgstr " - SDL_kitchensink (MIT)" + +msgid " - argagg (MIT)" +msgstr " - argagg (MIT)" + +msgid " - libasound (LGPLv2.1)" +msgstr " - libasound (LGPLv2.1)" + +msgid " - libcurl (MIT/X derivate)" +msgstr " - libcurl (MIT/X derivate)" + +msgid " - libogg and libvorbis (own license)" +msgstr " - libogg and libvorbis (own license)" + +msgid " - libpng (own license)" +msgstr " - libpng (own license)" + +msgid " - libpulse (LGPLv2.1)" +msgstr " - libpulse (LGPLv2.1)" + +msgid " - libsndfile (LGPLv3)" +msgstr " - libsndfile (LGPLv3)" + +msgid " - zlib (own license)" +msgstr " - zlib (own license)" + +msgid "(isolated tower)" +msgstr "(מגדל מבודד)" + +msgid "" +"1: Cut down a tree \n" +"2: Build a bridge" +msgstr "" +"1: לכרות עץ\n" +"2: לבנות גשר" + +msgid "" +"1: Cut down a tree \n" +"2: Make a boat" +msgstr "" +"1: לכרות עץ\n" +"2: לבנות סירה" + +msgid "" +"1: Cut down a tree \n" +"2: Make a palisade" +msgstr "" +"1: לכרות עץ\n" +"2: לבנות גדר" + +msgid "" +"1: Extract iron\n" +"2: Make a Jeep" +msgstr "" +"1: להפיק ברזל\n" +"2: לבנות ג'יפ" + +msgid "" +"1: Extract iron\n" +"2: Make a bomb" +msgstr "" +"1: להפיק ברזל\n" +"2: להכין פצצה" + +msgid "" +"1: Extract iron\n" +"2: Make an armour" +msgstr "" +"1: להפיק ברזל\n" +"2: לבנות מגן" + +msgid "" +"1: Grow tomatoes\n" +"2: Eat" +msgstr "" +"1: לגדל עגבניות\n" +"2: לאכול" + +msgid "" +"1: Make a bunch\n" +"2: Transform" +msgstr "" +"1: לאסוף\n" +"2: לשנות" + +msgid "" +"1: Take\n" +"2: Build a bridge" +msgstr "" +"1: לקחת\n" +"2: לבנות גשר" + +msgid "" +"1: Take\n" +"2: Build palisade" +msgstr "" +"1: לקחת\n" +"2: לבנות גדר" + +msgid "" +"1: Take\n" +"2: Make a boat" +msgstr "" +"1: לקחת\n" +"2: לבנות סירה" + +msgid "" +"1: Take\n" +"2: Transform" +msgstr "" +"1: לקחת\n" +"2: לשנות" + +msgid "" +"1|Drop planks on striped \n" +"1|paving stones." +msgstr "" +"1|הורידו את הקרשים על\n" +"1|המרצפות המפוספסות" + +msgid "" +"1|Drop platinium on striped \n" +"1|paving stones." +msgstr "" +"1|הורידו את הפלטינה על\n" +"1|המרצפות המפוספסות" + +msgid "" +"1|Drop tomatoes on striped \n" +"1|paving stones." +msgstr "" +"1|הורידו את העגבניות על\n" +"1|המרצפות המפוספסות" + +msgid "" +"1|Each Blupi in\n" +"1|his house." +msgstr "" +"1|כל בלופי\n" +"1|לביתו" + +msgid "" +"1|Go on striped\n" +"1|paving stones." +msgstr "" +"1|לכו אל המרצפות\n" +"1|המפוספסות" + +msgid "1|Goal :" +msgstr "1|מטרה:" + +msgid "" +"1|Kill all\n" +"1|enemies !" +msgstr "" +"1|הרגו את כל\n" +"1|האוייבים" + +msgid "" +"1|Resist until\n" +"1|fire extinction ..." +msgstr "" +"1|התנגדו לאש עד\n" +"1|שתכבה" + +#, c-format +msgid "" +"1|The Blupi population must\n" +"1|be of at least %d Blupi." +msgstr "" +"1|אוכלוסיית הבלופים חייבת \n" +"1|להיות לפחות %d בלופים" + +msgid "" +"1|The robot must reach\n" +"1|the striped paving stones." +msgstr "" +"1|הרובוט חייב להגיע אל\n" +"1|המרצפות המפוספסות" + +msgid "Aliasing" +msgstr "ללא החלקה" + +msgid "All licenses are available under share/doc/planetblupi/copyright" +msgstr "כל הרישיונות זמינים תחת share/doc/planetblupi/copyright" + +msgid "Already two teleporters" +msgstr "יש כבר שני משגרים" + +msgid "Another mistake..." +msgstr "עוד טעות!" + +msgid "Anti-aliasing" +msgstr "החלקת עקומות" + +msgid "Armour" +msgstr "שיריון" + +msgid "Available buttons" +msgstr "כפתורים זמינים" + +msgid "Bang, failed again !" +msgstr "בום! שוב נכשלתם!" + +msgid "Bank" +msgstr "גדה" + +msgid "Blow up" +msgstr "לפוצץ" + +msgid "Blupi" +msgstr "בלופי" + +msgid "Blupi in house" +msgstr "בלופי בתוך הבית" + +msgid "Blupi on striped paving stones" +msgstr "בלופי על המרצפות המפוספסות" + +msgid "Blupi's energy" +msgstr "האנרגיה של בלופי" + +msgid "Blupi's house" +msgstr "הבית של בלופי" + +msgid "Boat" +msgstr "סירה" + +msgid "Bouncing bomb" +msgstr "להקפיץ פצצה" + +msgid "Bridge" +msgstr "גשר" + +msgid "Bridge finished" +msgstr "גשר גמור" + +msgid "Buildings" +msgstr "בניינים" + +msgid "Bulldozer" +msgstr "דחפור" + +msgid "Bunch of flowers" +msgstr "זר פרחים" + +msgid "Burnt ground" +msgstr "אדמה שרופה" + +msgid "Cancel last operation" +msgstr "בטל פעולה אחרונה" + +msgid "Carve a rock" +msgstr "לחצוב בסלע" + +msgid "Carve rocks" +msgstr "לחצוב סלעים" + +msgid "" +"Change the\n" +"display mode" +msgstr "" +"שינוי\n" +"מצב התצוגה" + +msgid "" +"Change the\n" +"render quality" +msgstr "" +"שינוי\n" +"איכות המסירה" + +msgid "" +"Change the\n" +"window size" +msgstr "" +"שינוי\n" +"גודל החלון" + +msgid "" +"Choose the\n" +"music format" +msgstr "" +"בחירת\n" +"תסדיר המוזיקה" + +msgid "Construct this game" +msgstr "הרכב את המשחק" + +msgid "Construction" +msgstr "בנייה" + +msgid "Construction number" +msgstr "בנייה מספר" + +msgid "Continue this game" +msgstr "המשך משחק נוכחי" + +msgid "Cut down a tree" +msgstr "לכרות עץ" + +msgid "Cut down trees" +msgstr "לכרות עצים" + +msgid "Decorative plants" +msgstr "צמחי נוי" + +msgid "Delete figure" +msgstr "מחק דמות" + +msgid "Delete fire" +msgstr "מחק אש" + +msgid "Delete item" +msgstr "מחק פריט" + +msgid "Demo" +msgstr "הדגמה" + +msgid "Desert" +msgstr "מדבר" + +msgid "Desktop" +msgstr "שולחן עבודה" + +msgid "Desktop mode" +msgstr "מצב שולחן העבודה" + +msgid "Difficult" +msgstr "קשה" + +msgid "Disable anti-aliasing" +msgstr "נטרול החלקת עקומות" + +msgid "Drink" +msgstr "לשתות" + +msgid "Drop" +msgstr "להפיל" + +msgid "Dynamite" +msgstr "חומר נפץ" + +msgid "E" +msgstr "מז" + +msgid "Easy" +msgstr "קל" + +msgid "Eat" +msgstr "לאכול" + +msgid "Eggs" +msgstr "ביצים" + +msgid "Electrocutor" +msgstr "מחשמל" + +msgid "Enable anti-aliasing" +msgstr "הפעלת החלקת עקומות" + +msgid "Ending conditions" +msgstr "תנאים לסיום" + +msgid "Enemy barrier" +msgstr "מחסום האויב" + +msgid "Enemy buildings" +msgstr "בנייני האויב" + +msgid "Enemy construction" +msgstr "מבנה האויב" + +msgid "Enemy ground" +msgstr "אדמת אויב" + +msgid "Enemy rocket" +msgstr "טיל האויב" + +msgid "Excellent..." +msgstr "נהדר" + +msgid "Extract iron" +msgstr "להפיק ברזל" + +msgid "Faster" +msgstr "מהיר" + +msgid "Finish" +msgstr "סיום" + +msgid "Fire" +msgstr "אש" + +msgid "Fire out" +msgstr "אש כובתה" + +msgid "Flag" +msgstr "דגל" + +msgid "Flowers" +msgstr "פרחים" + +msgid "Forest" +msgstr "יער" + +msgid "Forest under snow" +msgstr "יער מתחת לשלג" + +msgid "Fullscreen" +msgstr "מסך מלא" + +msgid "Game paused" +msgstr "המשחק נעצר" + +msgid "Garden shed" +msgstr "חלקת גינה" + +msgid "" +"Global game\n" +"speed" +msgstr "" +"מהירות\n" +"משחק כוללת" + +msgid "Global settings" +msgstr "הגדרות כלליות" + +msgid "Go" +msgstr "המשך" + +msgid "Grow tomatoes" +msgstr "לגדל עגבניות" + +msgid "Help" +msgstr "עזרה" + +msgid "Help number" +msgstr "עזרה מספר" + +msgid "Helper robot" +msgstr "רובוט עוזר" + +msgid "Ice" +msgstr "קרח" + +msgid "Impossible" +msgstr "בלתי אפשרי" + +#, c-format +msgid "Impossible to win if less than %d Blupi" +msgstr "בלתי אפשרי לנצח אם פחות מ %d בלופים" + +msgid "Inadequate ground" +msgstr "קרקע לא מתאימה" + +msgid "Increase volume" +msgstr "הגברת עוצמה" + +msgid "Increase window size" +msgstr "להגדיל את גודל החלון" + +msgid "Incubator" +msgstr "מדגרה" + +msgid "Incubator or teleporter" +msgstr "מדגרה או משגר" + +msgid "Inflammable ground" +msgstr "קרקע דליקה" + +msgid "Insert CD-Rom Planet Blupi and wait a few seconds..." +msgstr "אנא הכנס את תקליטור המשחק וחכה מספר שניות" + +msgid "" +"Interface language\n" +"and sounds" +msgstr "" +"שפת הממשק\n" +"וצלילים" + +msgid "Interrupt" +msgstr "להפסיק" + +msgid "Iron" +msgstr "ברזל" + +msgid "Items" +msgstr "פריטים" + +msgid "Jeep" +msgstr "ג'יפ" + +msgid "Laboratory" +msgstr "מעבדה" + +msgid "Last construction resolved !" +msgstr "הבנייה האחרונה נפתרה!" + +msgid "Leave Jeep" +msgstr "לעזוב את הג'יפ" + +msgid "Legacy" +msgstr "גרסה ישנה" + +msgid "Legacy mode (640x480)" +msgstr "מצב גרסה ישנה(640x480)" + +#, c-format +msgid "Lost if less than %d Blupi" +msgstr "אבוד אם פחות מ %d בלופים" + +msgid "Make a Jeep" +msgstr "לבנות ג'יפ" + +msgid "Make a helper robot" +msgstr "לבנות רובוט עוזר" + +msgid "Make a time bomb" +msgstr "לבנות פצצת זמן" + +msgid "Make armour" +msgstr "לבנות שריון" + +msgid "Make bunch of flowers" +msgstr "לאסוף זר פרחים" + +msgid "Make bunches of flowers" +msgstr "לאסוף זרי פרחים" + +msgid "Master robot" +msgstr "הרובוט העליון" + +msgid "Medical potion" +msgstr "שיקוי רפואי" + +msgid "Midi" +msgstr "Midi" + +msgid "Mine" +msgstr "מכרה" + +msgid "Miscellaneous ground" +msgstr "קרקע מגוונת" + +msgid "Mission number" +msgstr "משימה מספר" + +msgid "Mission over..." +msgstr "המשימה הסתיימה..." + +msgid "Missions" +msgstr "משימות" + +msgid "" +"Music\n" +"volume" +msgstr "" +"עוצמת\n" +"המוזיקה" + +msgid "Music choice" +msgstr "בחירת מוסיקה" + +msgid "Music number 1" +msgstr "מוסיקה מספר 1" + +msgid "Music number 10" +msgstr "מוסיקה מספר 10" + +msgid "Music number 2" +msgstr "מוסיקה מספר 2" + +msgid "Music number 3" +msgstr "מוסיקה מספר 3" + +msgid "Music number 4" +msgstr "מוסיקה מספר 4" + +msgid "Music number 5" +msgstr "מוסיקה מספר 5" + +msgid "Music number 6" +msgstr "מוסיקה מספר 6" + +msgid "Music number 7" +msgstr "מוסיקה מספר 7" + +msgid "Music number 8" +msgstr "מוסיקה מספר 8" + +msgid "Music number 9" +msgstr "מוסיקה מספר 9" + +msgid "N" +msgstr "צ" + +#, c-format +msgid "New version available for download on www.blupi.org (v%s)" +msgstr "גרסה חדשה זמינה להורדה בכתובת www.blupi.org (v%s)" + +msgid "Next game" +msgstr "משחק הבא" + +msgid "Next language" +msgstr "שפה הבאה" + +msgid "Next page" +msgstr "הדף הבא" + +msgid "No" +msgstr "לא" + +msgid "No more enemies" +msgstr "אין יותר אויבים" + +msgid "No music" +msgstr "ללא מוסיקה" + +msgid "No video" +msgstr "בלי ווידאו" + +msgid "No, not that way !" +msgstr "לא! לא בדרך הזאת." + +msgid "No, wrong way ..." +msgstr "לא, זאת הדרך הלא נכונה." + +msgid "None" +msgstr "ללא גלילה" + +msgid "Normal ground" +msgstr "קרקע רגילה" + +msgid "Not available" +msgstr "לא זמין" + +msgid "Not enough energy" +msgstr "אין מספיק אנרגיה" + +msgid "Now go on mission." +msgstr "עכשיו התחילו בפעולה" + +msgid "Occupied ground" +msgstr "קרקע מאוכלסת" + +msgid "Ogg" +msgstr "Ogg" + +msgid "Open another game" +msgstr "טען משחק אחר" + +msgid "Opposite bank no good" +msgstr "הגדה ממול לא מתאימה" + +msgid "Palisade" +msgstr "גדר" + +msgid "Paving stones" +msgstr "מרצפות" + +msgid "Planet Blupi" +msgstr "הכוכב בלופי" + +msgid "Planet Blupi -- stop" +msgstr "הכוכב בלופי -- עצור" + +msgid "Planks" +msgstr "קרשים" + +msgid "Planks on striped paving stones" +msgstr "קרשים על האבנים המפוספסות" + +msgid "Platinium" +msgstr "פלטינה" + +msgid "Platinium on striped paving stones" +msgstr "פלטינה על המרצפות המפוספסות" + +msgid "Play this game" +msgstr "שחק במשחק הנוכחי" + +msgid "Poison" +msgstr "עגבניות מורעלות" + +msgid "Prairie" +msgstr "ערבה" + +msgid "Previous game" +msgstr "משחק קודם" + +msgid "Previous language" +msgstr "שפה קודמת" + +msgid "Previous page" +msgstr "דף קודם" + +msgid "Prospect for iron" +msgstr "לחפש ברזל" + +msgid "Protection tower" +msgstr "מגדל שמירה" + +msgid "Quit" +msgstr "צא" + +msgid "Quit Planet Blupi" +msgstr "צא מבלופי" + +msgid "Quit construction" +msgstr "יציאה מבנייה" + +msgid "Quit this game" +msgstr "צא ממשחק נוכחי" + +msgid "REC" +msgstr "הקלטה" + +msgid "Reduce volume" +msgstr "הפחתת עוצמה" + +msgid "Reduce window size" +msgstr "הפחתת גודל החלון" + +msgid "Repeat" +msgstr "חזור" + +msgid "Restart this game" +msgstr "התחל מחדש משחק נוכחי" + +msgid "Robot on striped paving stones" +msgstr "רובוט על המרצפות המפוספסות" + +msgid "Rocks" +msgstr "סלעים" + +msgid "S" +msgstr "ד" + +msgid "Save" +msgstr "שמור" + +msgid "Save this game" +msgstr "שמור משחק נוכחי" + +msgid "Scenery choice" +msgstr "בחירת נוף" + +msgid "" +"Scroll speed\n" +"with mouse" +msgstr "" +"מהירות גלילה\n" +"בעזרת עכבר" + +msgid "" +"Select the\n" +"window mode" +msgstr "" +"בחירת מצב\n" +"החלון" + +msgid "Settings" +msgstr "הגדרות" + +msgid "Show videos" +msgstr "הצג ווידאו" + +msgid "Sick Blupi" +msgstr "בלופי חולה" + +msgid "Skill level" +msgstr "דרגת מיומנות" + +msgid "Slower" +msgstr "איטי" + +msgid "" +"Sound effect\n" +"volume" +msgstr "" +"עוצמת האפקטים\n" +"הקוליים" + +msgid "Special pavings" +msgstr "ריצוף מיוחד" + +msgid "Spider" +msgstr "עכביש" + +msgid "Starting fire" +msgstr "הצת אש" + +msgid "Sterile ground" +msgstr "קרקע מחוטאת" + +msgid "Sticky trap" +msgstr "מלכודת דביקה" + +msgid "Stones" +msgstr "אבנים" + +msgid "Stop" +msgstr "עצור" + +msgid "Striped paving stones" +msgstr "מרצפות מפוספסות" + +msgid "Take" +msgstr "לקחת" + +msgid "Teleporter" +msgstr "משגר" + +msgid "" +"This game is an original creation of Epsitec SA, CH-1400 Yverdon-les-Bains" +msgstr "זהו משחק מקורי מאת Epsitec SA, CH-1400 Yverdon-les-Bains" + +msgid "This game uses statically linked free and open-source libraries:" +msgstr "המשחק משתמש בספריות קוד מקור חינמיות פתוחות" + +msgid "Time bomb" +msgstr "פצצת זמן" + +msgid "Tired Blupi" +msgstr "בלופי עייף" + +msgid "Tomatoes" +msgstr "עגבניות" + +msgid "Tomatoes on striped paving stones" +msgstr "עגבניות על המרצפות המפוספסות" + +msgid "Too close to water" +msgstr "קרוב מדי למים" + +msgid "Training" +msgstr "אימון" + +msgid "Training number" +msgstr "אימון מספר" + +msgid "Transform" +msgstr "לשנות" + +msgid "Transport" +msgstr "להוביל" + +msgid "Trapped enemy" +msgstr "אויב לכוד" + +msgid "Tree" +msgstr "עץ" + +msgid "Tree trunks" +msgstr "גזע עץ" + +msgid "Use Midi music (original)" +msgstr "שימוש במוזיקת Midi (מקור)" + +msgid "Use Ogg music" +msgstr "שימוש במוזיקת Ogg" + +msgid "Version" +msgstr "גרסה" + +msgid "Very good, success on all missions !" +msgstr "יפה מאוד! הצלחתם בכל המשימות!" + +msgid "Very good." +msgstr "ממש מעולה" + +msgid "" +"Video\n" +"sequences" +msgstr "" +"וידאו\n" +"רצף" + +msgid "Virus" +msgstr "וירוס" + +msgid "W" +msgstr "מע" + +msgid "Wall" +msgstr "חומה" + +msgid "Wall or palisade" +msgstr "חומה או גדר" + +msgid "Water" +msgstr "מים" + +msgid "We hope you have had as much fun playing the game as we had making it !" +msgstr "אנחנו מקווים שנהנתם לשחק במשחק לפחות כמו שנהננו ליצור אתו" + +msgid "Weapons" +msgstr "כלי נשק" + +msgid "Well done !" +msgstr "כל הכבוד!" + +msgid "Windowed" +msgstr "מצב חלון" + +msgid "Work done" +msgstr "העבודה הושלמה" + +msgid "Workshop" +msgstr "בית מלאכה" + +msgid "Yes" +msgstr "כן" + +msgid "Yes, great ..." +msgstr "כן, מצוין..." + +msgid "You have failed, try again..." +msgstr "נכשלתם, נסו שוב..." + +msgid "You have played Planet Blupi." +msgstr "שיחקתם בבלופי." + +#, c-format +msgid "construction %d, time %d" +msgstr "בנייה %d זמן %d" + +msgid "en" +msgstr "he" + +msgid "free slot" +msgstr "מקום פנוי" + +msgid "http://www.blupi.org info@blupi.org" +msgstr "http://www.blupi.org info@blupi.org" + +#, c-format +msgid "mission %d, time %d" +msgstr "פעולה %d זמן %d" + +#, c-format +msgid "training %d, time %d" +msgstr "אימון %d זמן %d" diff --git a/resources/po/it.po b/resources/po/it.po new file mode 100644 index 0000000..11f949a --- /dev/null +++ b/resources/po/it.po @@ -0,0 +1,989 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-08-08 07:29+0200\n" +"PO-Revision-Date: 2019-02-18 15:22+0100\n" +"Last-Translator: Mathieu Schroeter \n" +"Language-Team: \n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.2.1\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid " - FFmpeg (LGPLv2.1)" +msgstr " - FFmpeg (LGPLv2.1)" + +msgid " - GNU/gettext and GNU/libiconv (GPLv3)" +msgstr " - GNU/gettext e GNU/libiconv (GPLv3)" + +msgid " - SDL2, SDL2_image and SDL2_mixer (zlib license)" +msgstr " - SDL2, SDL2_image e SDL2_mixer (zlib licensa)" + +msgid " - SDL_kitchensink (MIT)" +msgstr " - SDL_kitchensink (MIT)" + +msgid " - argagg (MIT)" +msgstr " - argagg (MIT)" + +msgid " - libasound (LGPLv2.1)" +msgstr " - libasound (LGPLv2.1)" + +msgid " - libcurl (MIT/X derivate)" +msgstr " - libcurl (MIT/X derivata)" + +msgid " - libogg and libvorbis (own license)" +msgstr " - libogg and libvorbis (licensa personale)" + +msgid " - libpng (own license)" +msgstr " - libpng (licensa personale)" + +msgid " - libpulse (LGPLv2.1)" +msgstr " - libpulse (LGPLv2.1)" + +msgid " - libsndfile (LGPLv3)" +msgstr " - libsndfile (LGPLv3)" + +msgid " - zlib (own license)" +msgstr " - zlib (licensa personale)" + +msgid "(isolated tower)" +msgstr "(torre isolata)" + +msgid "" +"1: Cut down a tree \n" +"2: Build a bridge" +msgstr "" +"1: Abbatti un albero \n" +"2: Costruisci un ponte" + +msgid "" +"1: Cut down a tree \n" +"2: Make a boat" +msgstr "" +"1: Abbatti un albero \n" +"2: Costruisci una barca" + +msgid "" +"1: Cut down a tree \n" +"2: Make a palisade" +msgstr "" +"1: Abbatti un albero \n" +"2: Costruisci una palizzata" + +msgid "" +"1: Extract iron\n" +"2: Make a Jeep" +msgstr "" +"1: Estrai del ferro\n" +"2: Costruisci una Jeep" + +msgid "" +"1: Extract iron\n" +"2: Make a bomb" +msgstr "" +"1: Estrai del ferro\n" +"2: Costruisci una bomba" + +msgid "" +"1: Extract iron\n" +"2: Make an armour" +msgstr "" +"1: Estrai del ferro\n" +"2: Costruisci un'armatura" + +msgid "" +"1: Grow tomatoes\n" +"2: Eat" +msgstr "" +"1: Coltiva...\n" +"2: Mangia" + +msgid "" +"1: Make a bunch\n" +"2: Transform" +msgstr "" +"1: Fai un mazzo\n" +"2: Trasforma" + +msgid "" +"1: Take\n" +"2: Build a bridge" +msgstr "" +"1: Prendi\n" +"2: Costruisci un ponte" + +msgid "" +"1: Take\n" +"2: Build palisade" +msgstr "" +"1: Prendi\n" +"2: Costruisci una palizzata" + +msgid "" +"1: Take\n" +"2: Make a boat" +msgstr "" +"1: Prendi\n" +"2: Costruisci una barca" + +msgid "" +"1: Take\n" +"2: Transform" +msgstr "" +"1: Prendi\n" +"2: Trasforma" + +msgid "" +"1|Drop planks on striped \n" +"1|paving stones." +msgstr "" +"1|Posa delle assi \n" +"1|sulle lastre tratteggiate." + +msgid "" +"1|Drop platinium on striped \n" +"1|paving stones." +msgstr "" +"1|Posa del platinium sulle \n" +"1|lastre tratteggiate." + +msgid "" +"1|Drop tomatoes on striped \n" +"1|paving stones." +msgstr "" +"1|Posa dei pomodori sulle \n" +"1|lastre tratteggiate." + +msgid "" +"1|Each Blupi in\n" +"1|his house." +msgstr "" +"1|Ogni Blupi nella\n" +"1|sua casa." + +msgid "" +"1|Go on striped\n" +"1|paving stones." +msgstr "" +"1|Andare sulle lastre\n" +"1|tratteggiate." + +msgid "1|Goal :" +msgstr "1|Obbiettivo :" + +msgid "" +"1|Kill all\n" +"1|enemies !" +msgstr "" +"1|Eliminare\n" +"1|tutti i nemici !" + +msgid "" +"1|Resist until\n" +"1|fire extinction ..." +msgstr "" +"1|Resistere sino allo\n" +"1|spegnimento del fuoco ..." + +#, c-format +msgid "" +"1|The Blupi population must\n" +"1|be of at least %d Blupi." +msgstr "" +"1|La popolazione deve\n" +"1|essere di almeno %d Blupi." + +msgid "" +"1|The robot must reach\n" +"1|the striped paving stones." +msgstr "" +"1|Il robot deve raggiungere\n" +"1|le lastre tratteggiate." + +msgid "Aliasing" +msgstr "Aliasing" + +msgid "All licenses are available under share/doc/planetblupi/copyright" +msgstr "Tutte le license sono disponibili in share/doc/planetblupi/copyright" + +msgid "Already two teleporters" +msgstr "Esistono già due teletrasporti" + +msgid "Another mistake..." +msgstr "Ahimè, hai sbagliato un'altra volta..." + +msgid "Anti-aliasing" +msgstr "Anti-aliasing" + +msgid "Armour" +msgstr "Armatura" + +msgid "Available buttons" +msgstr "Pulsanti disponibili" + +msgid "Bang, failed again !" +msgstr "Bang, hai sbagliato ancora !" + +msgid "Bank" +msgstr "Riva" + +msgid "Blow up" +msgstr "Espoldi" + +msgid "Blupi" +msgstr "Blupi" + +msgid "Blupi in house" +msgstr "Blupi nella sua casa" + +msgid "Blupi on striped paving stones" +msgstr "Blupi su lastre tratteggiate" + +msgid "Blupi's energy" +msgstr "Energia di Blupi" + +msgid "Blupi's house" +msgstr "Casa di Blupi" + +msgid "Boat" +msgstr "Barca" + +msgid "Bouncing bomb" +msgstr "Bomba salterina" + +msgid "Bridge" +msgstr "Ponte" + +msgid "Bridge finished" +msgstr "Ponte finito" + +msgid "Buildings" +msgstr "Edifici" + +msgid "Bulldozer" +msgstr "Bulldozer" + +msgid "Bunch of flowers" +msgstr "Mazzo di fiori" + +msgid "Burnt ground" +msgstr "Terreno bruciato" + +msgid "Cancel last operation" +msgstr "Annullare l'ultima operazione" + +msgid "Carve a rock" +msgstr "Spacca una roccia" + +msgid "Carve rocks" +msgstr "Spacca delle roccie" + +msgid "" +"Change the\n" +"display mode" +msgstr "" +"Cambiare la\n" +"visualizzazione" + +msgid "" +"Change the\n" +"render quality" +msgstr "" +"Cambiare la\n" +"qualità\n" +"dell'immagina" + +msgid "" +"Change the\n" +"window size" +msgstr "" +"Cambiare la\n" +"dimensione\n" +"della finestra" + +msgid "" +"Choose the\n" +"music format" +msgstr "" +"Scegliere il\n" +"formato\n" +"della musica" + +msgid "Construct this game" +msgstr "Costruire questa partita" + +msgid "Construction" +msgstr "Costruzione" + +msgid "Construction number" +msgstr "Costruzione numero" + +msgid "Continue this game" +msgstr "Continua la partita" + +msgid "Cut down a tree" +msgstr "Abbatti un albero" + +msgid "Cut down trees" +msgstr "Abbatti degli alberi" + +msgid "Decorative plants" +msgstr "Piante ornamentali" + +msgid "Delete figure" +msgstr "Elimina personaggio" + +msgid "Delete fire" +msgstr "Elimina il fuoco" + +msgid "Delete item" +msgstr "Elimina oggetto" + +msgid "Demo" +msgstr "Demo" + +msgid "Desert" +msgstr "Deserto" + +msgid "Desktop" +msgstr "Risoluzione" + +msgid "Desktop mode" +msgstr "Modo desktop" + +msgid "Difficult" +msgstr "Difficile" + +msgid "Disable anti-aliasing" +msgstr "Disattivare anti-aliasing" + +msgid "Drink" +msgstr "Bevi" + +msgid "Drop" +msgstr "Posa" + +msgid "Dynamite" +msgstr "Dinamite" + +msgid "E" +msgstr "E" + +msgid "Easy" +msgstr "Facile" + +msgid "Eat" +msgstr "Mangia" + +msgid "Eggs" +msgstr "Uova" + +msgid "Electrocutor" +msgstr "Folgoratore" + +msgid "Enable anti-aliasing" +msgstr "Attivare anti-aliasing" + +msgid "Ending conditions" +msgstr "" +"Condizioni per\n" +"concludere\n" +"la missione" + +msgid "Enemy barrier" +msgstr "Barriera nemica" + +msgid "Enemy buildings" +msgstr "Edifici nemici" + +msgid "Enemy construction" +msgstr "Costruzione nemica" + +msgid "Enemy ground" +msgstr "Terreno nemico" + +msgid "Enemy rocket" +msgstr "Razzo nemico" + +msgid "Excellent..." +msgstr "Eccellente..." + +msgid "Extract iron" +msgstr "Estrai del ferro" + +msgid "Faster" +msgstr "Veloce" + +msgid "Finish" +msgstr "Terminare" + +msgid "Fire" +msgstr "Fuoco" + +msgid "Fire out" +msgstr "Fuoco fermato" + +msgid "Flag" +msgstr "Bandiera" + +msgid "Flowers" +msgstr "Fiori" + +msgid "Forest" +msgstr "Foresta" + +msgid "Forest under snow" +msgstr "Foresta innevata" + +msgid "Fullscreen" +msgstr "Schermata intera" + +msgid "Game paused" +msgstr "Partita interrotta" + +msgid "Garden shed" +msgstr "Capanno" + +msgid "" +"Global game\n" +"speed" +msgstr "" +"Velocità\n" +"del gioco" + +msgid "Global settings" +msgstr "Configurazione globale" + +msgid "Go" +msgstr "Va" + +msgid "Grow tomatoes" +msgstr "Coltiva pomodori" + +msgid "Help" +msgstr "Aiuto" + +msgid "Help number" +msgstr "Aiuto numero" + +msgid "Helper robot" +msgstr "Robot aiutante" + +msgid "Ice" +msgstr "Ghiaccio" + +msgid "Impossible" +msgstr "Impossibile" + +#, c-format +msgid "Impossible to win if less than %d Blupi" +msgstr "Impossibile vincere se meno di %d Blupi" + +msgid "Inadequate ground" +msgstr "Terreno non adatto" + +msgid "Increase volume" +msgstr "Alza il volume" + +msgid "Increase window size" +msgstr "Aumentare la dimensione della finestra" + +msgid "Incubator" +msgstr "Incubatrice" + +msgid "Incubator or teleporter" +msgstr "Incubatrice o teletrasporto" + +msgid "Inflammable ground" +msgstr "Terreno infiammabile" + +msgid "Insert CD-Rom Planet Blupi and wait a few seconds..." +msgstr "Inserire il CD-Rom Planet Blupi e attendere qualche secondo ..." + +msgid "" +"Interface language\n" +"and sounds" +msgstr "" +"Lingua\n" +"dell'interfaccia\n" +"e dei suoni" + +msgid "Interrupt" +msgstr "Interrompere" + +msgid "Iron" +msgstr "Ferro" + +msgid "Items" +msgstr "Oggetti" + +msgid "Jeep" +msgstr "Jeep" + +msgid "Laboratory" +msgstr "Laboratorio" + +msgid "Last construction resolved !" +msgstr "Ultima costruzione risolta !" + +msgid "Leave Jeep" +msgstr "Lascia la Jeep" + +msgid "Legacy" +msgstr "Originale" + +msgid "Legacy mode (640x480)" +msgstr "Originale (640x480)" + +#, c-format +msgid "Lost if less than %d Blupi" +msgstr "Perso se meno di %d Blupi" + +msgid "Make a Jeep" +msgstr "Costruisci una Jeep" + +msgid "Make a helper robot" +msgstr "Costruisci un robot aiutante" + +msgid "Make a time bomb" +msgstr "Costruisci una bomba" + +msgid "Make armour" +msgstr "Costruisci un'armatura" + +msgid "Make bunch of flowers" +msgstr "Fai un mazzo di fiori" + +msgid "Make bunches of flowers" +msgstr "Fai dei mazzi di fiori" + +msgid "Master robot" +msgstr "Robot-capo" + +msgid "Medical potion" +msgstr "Pozione" + +msgid "Midi" +msgstr "Midi" + +msgid "Mine" +msgstr "Miniera" + +msgid "Miscellaneous ground" +msgstr "Terreno misto" + +msgid "Mission number" +msgstr "Missione numero" + +msgid "Mission over..." +msgstr "Missione compiuta..." + +msgid "Missions" +msgstr "Missioni" + +msgid "" +"Music\n" +"volume" +msgstr "" +"Volume\n" +"della musica" + +msgid "Music choice" +msgstr "Scelta della musica" + +msgid "Music number 1" +msgstr "Musica numero 1" + +msgid "Music number 10" +msgstr "Musica numero 10" + +msgid "Music number 2" +msgstr "Musica numero 2" + +msgid "Music number 3" +msgstr "Musica numero 3" + +msgid "Music number 4" +msgstr "Musica numero 4" + +msgid "Music number 5" +msgstr "Musica numero 5" + +msgid "Music number 6" +msgstr "Musica numero 6" + +msgid "Music number 7" +msgstr "Musica numero 7" + +msgid "Music number 8" +msgstr "Musica numero 8" + +msgid "Music number 9" +msgstr "Musica numero 9" + +msgid "N" +msgstr "N" + +#, c-format +msgid "New version available for download on www.blupi.org (v%s)" +msgstr "Nuova versione disponibile su www.blupi.org (v%s)" + +msgid "Next game" +msgstr "Partita successiva" + +msgid "Next language" +msgstr "Prossima lingua" + +msgid "Next page" +msgstr "Pagina successiva" + +msgid "No" +msgstr "No" + +msgid "No more enemies" +msgstr "Nemici eliminati" + +msgid "No music" +msgstr "Nessuna musica" + +msgid "No video" +msgstr "Nessun video" + +msgid "No, not that way !" +msgstr "Ma no, non così !" + +msgid "No, wrong way ..." +msgstr "Eh no, non è così ..." + +msgid "None" +msgstr "Nessuno" + +msgid "Normal ground" +msgstr "Terreno normale" + +msgid "Not available" +msgstr "Non disponibile" + +msgid "Not enough energy" +msgstr "Energia limitata" + +msgid "Now go on mission." +msgstr "Ora passa alle missioni." + +msgid "Occupied ground" +msgstr "Terreno occupato" + +msgid "Ogg" +msgstr "Ogg" + +msgid "Open another game" +msgstr "Apri un'altra partita" + +msgid "Opposite bank no good" +msgstr "Riva opposta non ok" + +msgid "Palisade" +msgstr "Palizzata" + +msgid "Paving stones" +msgstr "Lastre" + +msgid "Planet Blupi" +msgstr "Planet Blupi" + +msgid "Planet Blupi -- stop" +msgstr "Planet Blupi -- stop" + +msgid "Planks" +msgstr "Assi" + +msgid "Planks on striped paving stones" +msgstr "Assi su lastre tratteggiate" + +msgid "Platinium" +msgstr "Platinium" + +msgid "Platinium on striped paving stones" +msgstr "Platinium su lastre trattegiate" + +msgid "Play this game" +msgstr "Giocare questa partita" + +msgid "Poison" +msgstr "Veleno" + +msgid "Prairie" +msgstr "Prateria" + +msgid "Previous game" +msgstr "Partita precedente" + +msgid "Previous language" +msgstr "Lingua precedente" + +msgid "Previous page" +msgstr "Pagina precedente" + +msgid "Prospect for iron" +msgstr "Cerca del ferro" + +msgid "Protection tower" +msgstr "Torre di protezione" + +msgid "Quit" +msgstr "Lascia" + +msgid "Quit Planet Blupi" +msgstr "Lasciare Planet Blupi" + +msgid "Quit construction" +msgstr "Terminare la costruzione" + +msgid "Quit this game" +msgstr "Lasciare la partita" + +msgid "REC" +msgstr "REC" + +msgid "Reduce volume" +msgstr "Abbassa il volume" + +msgid "Reduce window size" +msgstr "Ridurre la dimesione della finestra" + +msgid "Repeat" +msgstr "Ripeti" + +msgid "Restart this game" +msgstr "Ricomincia la partita" + +msgid "Robot on striped paving stones" +msgstr "Robot su lastre tratteggiate" + +msgid "Rocks" +msgstr "Rocce" + +msgid "S" +msgstr "S" + +msgid "Save" +msgstr "Salvare" + +msgid "Save this game" +msgstr "Salvare questa partita" + +msgid "Scenery choice" +msgstr "Scelta degli scenari" + +msgid "" +"Scroll speed\n" +"with mouse" +msgstr "" +"Velocità\n" +"del mouse" + +msgid "" +"Select the\n" +"window mode" +msgstr "" +"Selezionare il\n" +"modo finestra" + +msgid "Settings" +msgstr "Configurazione" + +msgid "Show videos" +msgstr "Mostra i video" + +msgid "Sick Blupi" +msgstr "Blupi ammalato" + +msgid "Skill level" +msgstr "Livello di difficoltà" + +msgid "Slower" +msgstr "Lento" + +msgid "" +"Sound effect\n" +"volume" +msgstr "" +"Volume\n" +"degli effetti" + +msgid "Special pavings" +msgstr "Lastre speciali" + +msgid "Spider" +msgstr "Ragno" + +msgid "Starting fire" +msgstr "Inizio d'incendio" + +msgid "Sterile ground" +msgstr "Terreno sterile" + +msgid "Sticky trap" +msgstr "Trappola collosa" + +msgid "Stones" +msgstr "Pietre" + +msgid "Stop" +msgstr "Stop" + +msgid "Striped paving stones" +msgstr "Lastre tratteggiate" + +msgid "Take" +msgstr "Prendi" + +msgid "Teleporter" +msgstr "Teletrasporto" + +msgid "" +"This game is an original creation of Epsitec SA, CH-1400 Yverdon-les-Bains" +msgstr "" +"Questo gioco è una realizzazione originale di Epsitec SA, CH-1400 Yverdon-" +"les-Bains" + +msgid "This game uses statically linked free and open-source libraries:" +msgstr "Questo gioco utilizza delle librerie open-source:" + +msgid "Time bomb" +msgstr "Bomba a tempo" + +msgid "Tired Blupi" +msgstr "Blupi stanco" + +msgid "Tomatoes" +msgstr "Pomodori" + +msgid "Tomatoes on striped paving stones" +msgstr "Pomodori su lastre tratteggiate" + +msgid "Too close to water" +msgstr "Troppo vicino all'acqua" + +msgid "Training" +msgstr "Allenamento" + +msgid "Training number" +msgstr "Allenamento numero" + +msgid "Transform" +msgstr "Trasforma" + +msgid "Transport" +msgstr "Mezzi di trasporto" + +msgid "Trapped enemy" +msgstr "Nemico intrappolato" + +msgid "Tree" +msgstr "Alberi" + +msgid "Tree trunks" +msgstr "Tronchi" + +msgid "Use Midi music (original)" +msgstr "Utilizzare la musica Midi (originale)" + +msgid "Use Ogg music" +msgstr "Utilizzare la musica Ogg" + +msgid "Version" +msgstr "Versione" + +msgid "Very good, success on all missions !" +msgstr "Splendido, hai concluso il gioco !" + +msgid "Very good." +msgstr "Molto bene." + +msgid "" +"Video\n" +"sequences" +msgstr "" +"Sequenze\n" +"video" + +msgid "Virus" +msgstr "Virus" + +msgid "W" +msgstr "O" + +msgid "Wall" +msgstr "Muro" + +msgid "Wall or palisade" +msgstr "Muro o Palizzata" + +msgid "Water" +msgstr "Acqua" + +msgid "We hope you have had as much fun playing the game as we had making it !" +msgstr "" +"Speriamo che ti sia divertito con questo gioco almeno quanto noi ci siamo " +"zzarlo !" + +msgid "Weapons" +msgstr "Armi" + +msgid "Well done !" +msgstr "Bravo, ce l'hai fatta !" + +msgid "Windowed" +msgstr "Finestra" + +msgid "Work done" +msgstr "Lavoro in corso" + +msgid "Workshop" +msgstr "Fabbrica" + +msgid "Yes" +msgstr "Si" + +msgid "Yes, great ..." +msgstr "Si, fantastico ..." + +msgid "You have failed, try again..." +msgstr "Hai sbagliato, riprova..." + +msgid "You have played Planet Blupi." +msgstr "Hai giocato con Planet Blupi." + +#, c-format +msgid "construction %d, time %d" +msgstr "Costruzione %d, tempo %d" + +msgid "en" +msgstr "it" + +msgid "free slot" +msgstr "libero" + +msgid "http://www.blupi.org info@blupi.org" +msgstr "http://www.blupi.org info@blupi.org" + +#, c-format +msgid "mission %d, time %d" +msgstr "missione %d, tempo %d" + +#, c-format +msgid "training %d, time %d" +msgstr "allenamento %d, tempo %d" + +#, fuzzy +#~ msgid "Nearest" +#~ msgstr "Foresta" diff --git a/resources/po/pl.po b/resources/po/pl.po new file mode 100644 index 0000000..7f661cb --- /dev/null +++ b/resources/po/pl.po @@ -0,0 +1,984 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-08-08 07:29+0200\n" +"PO-Revision-Date: 2019-02-17 23:22+0100\n" +"Last-Translator: tomangelo \n" +"Language-Team: TerranovaTeam \n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" +"X-Generator: Poedit 2.2.1\n" + +msgid " - FFmpeg (LGPLv2.1)" +msgstr " - FFmpeg (LGPLv2.1)" + +msgid " - GNU/gettext and GNU/libiconv (GPLv3)" +msgstr " - GNU/gettext and GNU/libiconv (GPLv3)" + +msgid " - SDL2, SDL2_image and SDL2_mixer (zlib license)" +msgstr " - SDL2, SDL2_image and SDL2_mixer (licencja zlib)" + +msgid " - SDL_kitchensink (MIT)" +msgstr " - SDL_kitchensink (MIT)" + +msgid " - argagg (MIT)" +msgstr " - argagg (MIT)" + +msgid " - libasound (LGPLv2.1)" +msgstr " - libasound (LGPLv2.1)" + +msgid " - libcurl (MIT/X derivate)" +msgstr " - libcurl (MIT/X derivate)" + +msgid " - libogg and libvorbis (own license)" +msgstr " - libogg and libvorbis (własna licencja)" + +msgid " - libpng (own license)" +msgstr " - libpng (własna licencja)" + +msgid " - libpulse (LGPLv2.1)" +msgstr " - libpulse (LGPLv2.1)" + +msgid " - libsndfile (LGPLv3)" +msgstr " - libsndfile (LGPLv2.1)" + +msgid " - zlib (own license)" +msgstr " - zlib (własna licencja)" + +msgid "(isolated tower)" +msgstr "(samotna wieża)" + +msgid "" +"1: Cut down a tree \n" +"2: Build a bridge" +msgstr "" +"1: Zetnij drzewo\n" +"2: Zbuduj most" + +msgid "" +"1: Cut down a tree \n" +"2: Make a boat" +msgstr "" +"1: Zetnij drzewo\n" +"2: Zbuduj łódź" + +msgid "" +"1: Cut down a tree \n" +"2: Make a palisade" +msgstr "" +"1: Zetnij drzewo\n" +"2: Zbuduj palisadę" + +msgid "" +"1: Extract iron\n" +"2: Make a Jeep" +msgstr "" +"1: Wykop żelazo\n" +"2: Stwórz Jeepa" + +msgid "" +"1: Extract iron\n" +"2: Make a bomb" +msgstr "" +"1: Wykop żelazo\n" +"2: Stwórz bombę" + +msgid "" +"1: Extract iron\n" +"2: Make an armour" +msgstr "" +"1: Wykop żelazo\n" +"2: Stwórz zbroję" + +msgid "" +"1: Grow tomatoes\n" +"2: Eat" +msgstr "" +"1: Zasadź pomidory\n" +"2: Zjedz" + +msgid "" +"1: Make a bunch\n" +"2: Transform" +msgstr "" +"1: Zbierz wiele\n" +"2: Przetwórz" + +msgid "" +"1: Take\n" +"2: Build a bridge" +msgstr "" +"1: Weź\n" +"2: Zbuduj most" + +msgid "" +"1: Take\n" +"2: Build palisade" +msgstr "" +"1: Weź\n" +"2: Zbuduj palisadę" + +msgid "" +"1: Take\n" +"2: Make a boat" +msgstr "" +"1: Weź\n" +"2: Zbuduj łódź" + +msgid "" +"1: Take\n" +"2: Transform" +msgstr "" +"1: Weź\n" +"2: Przetwórz" + +msgid "" +"1|Drop planks on striped \n" +"1|paving stones." +msgstr "" +"1|Połóż deski na\n" +"1|nawierzchni docelowej." + +msgid "" +"1|Drop platinium on striped \n" +"1|paving stones." +msgstr "" +"1|Połóż platynę na\n" +"1|nawierzchni docelowej." + +msgid "" +"1|Drop tomatoes on striped \n" +"1|paving stones." +msgstr "" +"1|Połóż pomidory na\n" +"1|nawierzchni docelowej." + +msgid "" +"1|Each Blupi in\n" +"1|his house." +msgstr "" +"1|Każdy Blupi we\n" +"1|własnym domu." + +msgid "" +"1|Go on striped\n" +"1|paving stones." +msgstr "" +"1|Idź na\n" +"1|nawierzchnię docelową." + +msgid "1|Goal :" +msgstr "1|Zadanie :" + +msgid "" +"1|Kill all\n" +"1|enemies !" +msgstr "" +"1|Wyeliminuj wszystkich\n" +"1|przeciwników!" + +msgid "" +"1|Resist until\n" +"1|fire extinction ..." +msgstr "" +"1|Wytrzymaj dopóki\n" +"1|pożar nie wygaśnie ..." + +#, c-format +msgid "" +"1|The Blupi population must\n" +"1|be of at least %d Blupi." +msgstr "" +"1|Populacja Blupich musi\n" +"1|wynosić minimum %d Blupich." + +msgid "" +"1|The robot must reach\n" +"1|the striped paving stones." +msgstr "" +"1|Robot musi dotrzeć do\n" +"1|nawierzchni docelowej." + +msgid "Aliasing" +msgstr "Pikselizacja" + +msgid "All licenses are available under share/doc/planetblupi/copyright" +msgstr "Wszystkie licencje dostępne są w share/doc/planetblupi/copyright" + +msgid "Already two teleporters" +msgstr "Już istnieją 2 teleportery" + +msgid "Another mistake..." +msgstr "Znowu pomyłka..." + +msgid "Anti-aliasing" +msgstr "Wygładzanie" + +msgid "Armour" +msgstr "Zbroja" + +msgid "Available buttons" +msgstr "Dostępne przyciski" + +msgid "Bang, failed again !" +msgstr "Motyla noga, znowu porażka!" + +msgid "Bank" +msgstr "Brzeg" + +msgid "Blow up" +msgstr "Wysadź w powietrze" + +msgid "Blupi" +msgstr "Blupi" + +msgid "Blupi in house" +msgstr "Blupi w domu" + +msgid "Blupi on striped paving stones" +msgstr "Blupi na nawierzchni docelowej" + +msgid "Blupi's energy" +msgstr "Siła Blupiego" + +msgid "Blupi's house" +msgstr "Domek Blupiego" + +msgid "Boat" +msgstr "Łódź" + +msgid "Bouncing bomb" +msgstr "Skacząca bomba" + +msgid "Bridge" +msgstr "Most" + +msgid "Bridge finished" +msgstr "Most skończony" + +msgid "Buildings" +msgstr "Budynki" + +msgid "Bulldozer" +msgstr "Buldożer" + +msgid "Bunch of flowers" +msgstr "Bukiet kwiatów" + +msgid "Burnt ground" +msgstr "Wypalona ziemia" + +msgid "Cancel last operation" +msgstr "Cofnij ostatnią operację" + +msgid "Carve a rock" +msgstr "Wyłup skałę" + +msgid "Carve rocks" +msgstr "Wyłup skały" + +msgid "" +"Change the\n" +"display mode" +msgstr "" +"Zmień tryb\n" +"wyświetlania" + +msgid "" +"Change the\n" +"render quality" +msgstr "" +"Zmień jakość\n" +"renderowania" + +msgid "" +"Change the\n" +"window size" +msgstr "" +"Zmień rozmiar\n" +"okna" + +msgid "" +"Choose the\n" +"music format" +msgstr "" +"Wybierz format\n" +"muzyki" + +msgid "Construct this game" +msgstr "Edytuj poziom" + +msgid "Construction" +msgstr "Konstrukcja" + +msgid "Construction number" +msgstr "Konstrukcja numer" + +msgid "Continue this game" +msgstr "Kontynuuj" + +msgid "Cut down a tree" +msgstr "Zetnij drzewo" + +msgid "Cut down trees" +msgstr "Zetnij drzewa" + +msgid "Decorative plants" +msgstr "Rośliny ozdobne" + +msgid "Delete figure" +msgstr "Usuń postać" + +msgid "Delete fire" +msgstr "Usuń ogień" + +msgid "Delete item" +msgstr "Usuń przedmiot" + +msgid "Demo" +msgstr "Demonstracja" + +msgid "Desert" +msgstr "Pustynia" + +msgid "Desktop" +msgstr "Pulpit" + +msgid "Desktop mode" +msgstr "Tryb pulpitu" + +msgid "Difficult" +msgstr "Trudny" + +msgid "Disable anti-aliasing" +msgstr "Wyłącz wygładzanie" + +msgid "Drink" +msgstr "Wypij" + +msgid "Drop" +msgstr "Upuść" + +msgid "Dynamite" +msgstr "Dynamit" + +msgid "E" +msgstr "Ws" + +msgid "Easy" +msgstr "Prosty" + +msgid "Eat" +msgstr "Jedz" + +msgid "Eggs" +msgstr "Jaja" + +msgid "Electrocutor" +msgstr "Paralizator" + +msgid "Enable anti-aliasing" +msgstr "Włącz wygładzanie" + +msgid "Ending conditions" +msgstr "Warunki zwycięstwa" + +msgid "Enemy barrier" +msgstr "Wroga bariera" + +msgid "Enemy buildings" +msgstr "Wrogie budynki" + +msgid "Enemy construction" +msgstr "Wroga konstrukcja" + +msgid "Enemy ground" +msgstr "Wroga ziemia" + +msgid "Enemy rocket" +msgstr "Wroga rakieta" + +msgid "Excellent..." +msgstr "Doskonale..." + +msgid "Extract iron" +msgstr "Wykop żelazo" + +msgid "Faster" +msgstr "Szybciej" + +msgid "Finish" +msgstr "Zakończ" + +msgid "Fire" +msgstr "Ogień" + +msgid "Fire out" +msgstr "Ugaszony pożar" + +msgid "Flag" +msgstr "Flaga" + +msgid "Flowers" +msgstr "Kwiaty" + +msgid "Forest" +msgstr "Las" + +msgid "Forest under snow" +msgstr "Las pokryty śniegiem" + +msgid "Fullscreen" +msgstr "Pełny ekran" + +msgid "Game paused" +msgstr "Gra zapauzowana" + +msgid "Garden shed" +msgstr "Szopka ogrodowa" + +msgid "" +"Global game\n" +"speed" +msgstr "" +"Prędkość\n" +"gry" + +msgid "Global settings" +msgstr "Ustawienia" + +msgid "Go" +msgstr "Idź" + +msgid "Grow tomatoes" +msgstr "Sadź pomidory" + +msgid "Help" +msgstr "Pomoc" + +msgid "Help number" +msgstr "Pomoc numer" + +msgid "Helper robot" +msgstr "Robot-pomocnik" + +msgid "Ice" +msgstr "Lód" + +msgid "Impossible" +msgstr "Niemożliwe" + +#, c-format +msgid "Impossible to win if less than %d Blupi" +msgstr "Niemożliwe do wygrania jeśli mniej niż %d Blupich" + +msgid "Inadequate ground" +msgstr "Nieodpowiedni teren" + +msgid "Increase volume" +msgstr "Zwiększ głośność" + +msgid "Increase window size" +msgstr "Zwiększ rozmiar okna" + +msgid "Incubator" +msgstr "Wylęgarka" + +msgid "Incubator or teleporter" +msgstr "Inkubator lub teleporter" + +msgid "Inflammable ground" +msgstr "Łatwopalna ziemia" + +msgid "Insert CD-Rom Planet Blupi and wait a few seconds..." +msgstr "" +"Włóż płytę CD-ROM z grą Planet Blupi do napędu optycznego i poczekaj kilka " +"sekund" + +msgid "" +"Interface language\n" +"and sounds" +msgstr "" +"Język interfejsu\n" +"oraz dźwięków" + +msgid "Interrupt" +msgstr "Przerwij" + +msgid "Iron" +msgstr "Żelazo" + +msgid "Items" +msgstr "Przedmioty" + +msgid "Jeep" +msgstr "Jeep" + +msgid "Laboratory" +msgstr "Laboratorium" + +msgid "Last construction resolved !" +msgstr "Ostatnia łamigłówka rozwiązana!" + +msgid "Leave Jeep" +msgstr "Opuść Jeepa" + +msgid "Legacy" +msgstr "Zgodność" + +msgid "Legacy mode (640x480)" +msgstr "Tryb zgodności (640x480)" + +#, c-format +msgid "Lost if less than %d Blupi" +msgstr "Przegrana jeśli mniej niż %d Blupich" + +msgid "Make a Jeep" +msgstr "Stwórz Jeepa" + +msgid "Make a helper robot" +msgstr "Stwórz robota-pomocnika" + +msgid "Make a time bomb" +msgstr "Stwórz bombę zegarową" + +msgid "Make armour" +msgstr "Stwórz zbroję" + +msgid "Make bunch of flowers" +msgstr "Ułóż bukiet kwiatów" + +msgid "Make bunches of flowers" +msgstr "Ułóż bukiety kwiatów" + +msgid "Master robot" +msgstr "Mistrz robotów" + +msgid "Medical potion" +msgstr "Lekarstwo" + +msgid "Midi" +msgstr "Midi" + +msgid "Mine" +msgstr "Kopalnia" + +msgid "Miscellaneous ground" +msgstr "Mieszana ziemia" + +msgid "Mission number" +msgstr "Misja numer" + +msgid "Mission over..." +msgstr "Koniec zadania..." + +msgid "Missions" +msgstr "Misje" + +msgid "" +"Music\n" +"volume" +msgstr "" +"Głośność\n" +"muzyki" + +msgid "Music choice" +msgstr "Wybór muzyki" + +msgid "Music number 1" +msgstr "Muzyka numer 1" + +msgid "Music number 10" +msgstr "Muzyka numer 10" + +msgid "Music number 2" +msgstr "Muzyka numer 2" + +msgid "Music number 3" +msgstr "Muzyka numer 3" + +msgid "Music number 4" +msgstr "Muzyka numer 4" + +msgid "Music number 5" +msgstr "Muzyka numer 5" + +msgid "Music number 6" +msgstr "Muzyka numer 6" + +msgid "Music number 7" +msgstr "Muzyka numer 7" + +msgid "Music number 8" +msgstr "Muzyka numer 8" + +msgid "Music number 9" +msgstr "Muzyka numer 9" + +msgid "N" +msgstr "Pn" + +#, c-format +msgid "New version available for download on www.blupi.org (v%s)" +msgstr "Nowa wersja dostępna do pobrania na www.blupi.org (v%s)" + +msgid "Next game" +msgstr "Następne zadanie" + +msgid "Next language" +msgstr "Następny język" + +msgid "Next page" +msgstr "Następna strona" + +msgid "No" +msgstr "Nie" + +msgid "No more enemies" +msgstr "Brak przeciwników" + +msgid "No music" +msgstr "Brak muzyki" + +msgid "No video" +msgstr "Brak wstawek filmowych" + +msgid "No, not that way !" +msgstr "Nie, nie w ten sposób!" + +msgid "No, wrong way ..." +msgstr "Nie, nie tak..." + +msgid "None" +msgstr "Brak" + +msgid "Normal ground" +msgstr "Zwykła ziemia" + +msgid "Not available" +msgstr "Niedostępne" + +msgid "Not enough energy" +msgstr "Za mało siły" + +msgid "Now go on mission." +msgstr "Teraz spróbuj swoich sił w misjach" + +msgid "Occupied ground" +msgstr "Teren zajęty" + +msgid "Ogg" +msgstr "Ogg" + +msgid "Open another game" +msgstr "Otwórz poprzednią grę" + +msgid "Opposite bank no good" +msgstr "Brzeg nie jest odpowiedni" + +msgid "Palisade" +msgstr "Palisada" + +msgid "Paving stones" +msgstr "Kostka brukowa" + +msgid "Planet Blupi" +msgstr "Planet Blupi" + +msgid "Planet Blupi -- stop" +msgstr "Planet Blupi -- zatrzymano" + +msgid "Planks" +msgstr "Deski" + +msgid "Planks on striped paving stones" +msgstr "Deski na nawierzchni docelowej" + +msgid "Platinium" +msgstr "Platyna" + +msgid "Platinium on striped paving stones" +msgstr "Platyna na nawierzchni docelowej" + +msgid "Play this game" +msgstr "Zagraj" + +msgid "Poison" +msgstr "Trucizna" + +msgid "Prairie" +msgstr "Preria" + +msgid "Previous game" +msgstr "Poprzednie zadanie" + +msgid "Previous language" +msgstr "Poprzedni język" + +msgid "Previous page" +msgstr "Poprzednia strona" + +msgid "Prospect for iron" +msgstr "Szukaj żelaza" + +msgid "Protection tower" +msgstr "Wieża obronna" + +msgid "Quit" +msgstr "Wyjdź" + +msgid "Quit Planet Blupi" +msgstr "Wyjdź z Planet Blupi" + +msgid "Quit construction" +msgstr "Zakończ tworzenie" + +msgid "Quit this game" +msgstr "Opuść tą grę" + +msgid "REC" +msgstr "Nagrywanie" + +msgid "Reduce volume" +msgstr "Zmniejsz głośność" + +msgid "Reduce window size" +msgstr "Zmniejsz rozmiar okna" + +msgid "Repeat" +msgstr "Powtórz" + +msgid "Restart this game" +msgstr "Uruchom grę ponownie" + +msgid "Robot on striped paving stones" +msgstr "Roboty na nawierzchni docelowej" + +msgid "Rocks" +msgstr "Skały" + +msgid "S" +msgstr "Pd" + +msgid "Save" +msgstr "Zapisz" + +msgid "Save this game" +msgstr "Zapisz tą grę" + +msgid "Scenery choice" +msgstr "Wybór scenerii" + +msgid "" +"Scroll speed\n" +"with mouse" +msgstr "" +"Prędkość przewijania\n" +"myszą" + +msgid "" +"Select the\n" +"window mode" +msgstr "" +"Wybierz\n" +"tryb okienkowy" + +msgid "Settings" +msgstr "Opcje" + +msgid "Show videos" +msgstr "Pokaż wstawki filmowe" + +msgid "Sick Blupi" +msgstr "Zarażony Blupi" + +msgid "Skill level" +msgstr "Poziom trudności" + +msgid "Slower" +msgstr "Wolniej" + +msgid "" +"Sound effect\n" +"volume" +msgstr "" +"Głośność\n" +"efektów" + +msgid "Special pavings" +msgstr "Specjalne nawierzchnie" + +msgid "Spider" +msgstr "Pająk" + +msgid "Starting fire" +msgstr "Początek pożaru" + +msgid "Sterile ground" +msgstr "Jałowa ziemia" + +msgid "Sticky trap" +msgstr "Klejąca pułapka" + +msgid "Stones" +msgstr "Kamienie" + +msgid "Stop" +msgstr "Przerwij" + +msgid "Striped paving stones" +msgstr "Nawierzchnia docelowa" + +msgid "Take" +msgstr "Weź" + +msgid "Teleporter" +msgstr "Teleporter" + +msgid "" +"This game is an original creation of Epsitec SA, CH-1400 Yverdon-les-Bains" +msgstr "Ta gra to oryginalne dzieło Epsitec SA, CH-1400 Yverdon-les-Bains" + +msgid "This game uses statically linked free and open-source libraries:" +msgstr "" +"Ta gra używa statystycznie linkowanych wolnych i otwartoźródłowych " +"bibliotek: " + +msgid "Time bomb" +msgstr "Bomba zegarowa" + +msgid "Tired Blupi" +msgstr "Zmęczony Blupi" + +msgid "Tomatoes" +msgstr "Pomidory" + +msgid "Tomatoes on striped paving stones" +msgstr "Pomidory na nawierzchni docelowej" + +msgid "Too close to water" +msgstr "Za blisko wody" + +msgid "Training" +msgstr "Trening" + +msgid "Training number" +msgstr "Trening numer" + +msgid "Transform" +msgstr "Przetwórz" + +msgid "Transport" +msgstr "Środki transportu" + +msgid "Trapped enemy" +msgstr "Przyklejony przeciwnik" + +msgid "Tree" +msgstr "Drzewo" + +msgid "Tree trunks" +msgstr "Pnie drzew" + +msgid "Use Midi music (original)" +msgstr "Muzyka Midi (oryginalna)" + +msgid "Use Ogg music" +msgstr "Muzyka Ogg" + +msgid "Version" +msgstr "Wersja" + +msgid "Very good, success on all missions !" +msgstr "Bardzo dobrze, suksesów we wszystkich misjach" + +msgid "Very good." +msgstr "Bardzo dobrze." + +msgid "" +"Video\n" +"sequences" +msgstr "" +"Wstawki\n" +"filmowe" + +msgid "Virus" +msgstr "Wirus" + +msgid "W" +msgstr "Za" + +msgid "Wall" +msgstr "Mur" + +msgid "Wall or palisade" +msgstr "Mur lub palisada" + +msgid "Water" +msgstr "Woda" + +msgid "We hope you have had as much fun playing the game as we had making it !" +msgstr "" +"Mamy nadzieję że miałeś tak dużo frajdy z gry jak my gdy ją tworzyliśmy!" + +msgid "Weapons" +msgstr "Bronie" + +msgid "Well done !" +msgstr "Dobra robota!" + +msgid "Windowed" +msgstr "Tryb okienkowy" + +msgid "Work done" +msgstr "Zadanie skończone" + +msgid "Workshop" +msgstr "Warsztat" + +msgid "Yes" +msgstr "Tak" + +msgid "Yes, great ..." +msgstr "Tak, wspaniale ..." + +msgid "You have failed, try again..." +msgstr "Przegrałeś, spróbuj ponownie..." + +msgid "You have played Planet Blupi." +msgstr "Grałeś w Planet Blupi" + +#, c-format +msgid "construction %d, time %d" +msgstr "Budowanie %d, czas %d" + +msgid "en" +msgstr "pl" + +msgid "free slot" +msgstr "Wolny slot" + +msgid "http://www.blupi.org info@blupi.org" +msgstr "http://www.blupi.org info@blupi.org" + +#, c-format +msgid "mission %d, time %d" +msgstr "Misja %d, czas %d" + +#, c-format +msgid "training %d, time %d" +msgstr "Trenowanie %d, czas %d" + +#, fuzzy +#~ msgid "Nearest" +#~ msgstr "Las" diff --git a/resources/po/planetblupi.pot b/resources/po/planetblupi.pot new file mode 100644 index 0000000..36bc15f --- /dev/null +++ b/resources/po/planetblupi.pot @@ -0,0 +1,909 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-02-17 14:11+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "Planet Blupi" +msgstr "" + +msgid "Planet Blupi -- stop" +msgstr "" + +msgid "" +"1: Grow tomatoes\n" +"2: Eat" +msgstr "" + +msgid "" +"1: Make a bunch\n" +"2: Transform" +msgstr "" + +msgid "" +"1: Take\n" +"2: Transform" +msgstr "" + +msgid "" +"1: Extract iron\n" +"2: Make a bomb" +msgstr "" + +msgid "" +"1: Extract iron\n" +"2: Make a Jeep" +msgstr "" + +msgid "" +"1: Extract iron\n" +"2: Make an armour" +msgstr "" + +msgid "" +"1: Cut down a tree \n" +"2: Make a palisade" +msgstr "" + +msgid "" +"1: Take\n" +"2: Build palisade" +msgstr "" + +msgid "" +"1: Cut down a tree \n" +"2: Build a bridge" +msgstr "" + +msgid "" +"1: Take\n" +"2: Build a bridge" +msgstr "" + +msgid "" +"1: Cut down a tree \n" +"2: Make a boat" +msgstr "" + +msgid "" +"1: Take\n" +"2: Make a boat" +msgstr "" + +msgid "Tree" +msgstr "" + +msgid "Enemy rocket" +msgstr "" + +msgid "Platinium" +msgstr "" + +msgid "Armour" +msgstr "" + +msgid "Enemy construction" +msgstr "" + +msgid "Wall" +msgstr "" + +msgid "Protection tower" +msgstr "" + +msgid "Laboratory" +msgstr "" + +msgid "Tree trunks" +msgstr "" + +msgid "Planks" +msgstr "" + +msgid "Rocks" +msgstr "" + +msgid "Stones" +msgstr "" + +msgid "Fire" +msgstr "" + +msgid "Tomatoes" +msgstr "" + +msgid "Garden shed" +msgstr "" + +msgid "Eggs" +msgstr "" + +msgid "Palisade" +msgstr "" + +msgid "Bridge" +msgstr "" + +msgid "Medical potion" +msgstr "" + +msgid "Flowers" +msgstr "" + +msgid "Bunch of flowers" +msgstr "" + +msgid "Dynamite" +msgstr "" + +msgid "Poison" +msgstr "" + +msgid "Sticky trap" +msgstr "" + +msgid "Trapped enemy" +msgstr "" + +msgid "Blupi's house" +msgstr "" + +msgid "Boat" +msgstr "" + +msgid "Jeep" +msgstr "" + +msgid "Workshop" +msgstr "" + +msgid "Mine" +msgstr "" + +msgid "Iron" +msgstr "" + +msgid "Flag" +msgstr "" + +msgid "Time bomb" +msgstr "" + +msgid "Normal ground" +msgstr "" + +msgid "Bank" +msgstr "" + +msgid "Water" +msgstr "" + +msgid "Paving stones" +msgstr "" + +msgid "Striped paving stones" +msgstr "" + +msgid "Ice" +msgstr "" + +msgid "Burnt ground" +msgstr "" + +msgid "Inflammable ground" +msgstr "" + +msgid "Miscellaneous ground" +msgstr "" + +msgid "Sterile ground" +msgstr "" + +msgid "Incubator" +msgstr "" + +msgid "Enemy ground" +msgstr "" + +msgid "Teleporter" +msgstr "" + +msgid "Tired Blupi" +msgstr "" + +msgid "Sick Blupi" +msgstr "" + +msgid "Blupi" +msgstr "" + +msgid "Spider" +msgstr "" + +msgid "Virus" +msgstr "" + +msgid "Bulldozer" +msgstr "" + +msgid "Master robot" +msgstr "" + +msgid "Bouncing bomb" +msgstr "" + +msgid "Electrocutor" +msgstr "" + +msgid "Helper robot" +msgstr "" + +msgid "Interrupt" +msgstr "" + +msgid "Settings" +msgstr "" + +msgid "Save" +msgstr "" + +msgid "Demo" +msgstr "" + +msgid "Training" +msgstr "" + +msgid "Missions" +msgstr "" + +msgid "Construction" +msgstr "" + +msgid "Global settings" +msgstr "" + +msgid "Quit Planet Blupi" +msgstr "" + +msgid "Previous page" +msgstr "" + +msgid "Next page" +msgstr "" + +msgid "Previous game" +msgstr "" + +msgid "Play this game" +msgstr "" + +msgid "Next game" +msgstr "" + +msgid "Open another game" +msgstr "" + +msgid "Construct this game" +msgstr "" + +msgid "Skill level" +msgstr "" + +msgid "Finish" +msgstr "" + +msgid "Continue this game" +msgstr "" + +msgid "Save this game" +msgstr "" + +msgid "Quit this game" +msgstr "" + +msgid "Help" +msgstr "" + +msgid "Slower" +msgstr "" + +msgid "Faster" +msgstr "" + +msgid "Reduce volume" +msgstr "" + +msgid "Increase volume" +msgstr "" + +msgid "No video" +msgstr "" + +msgid "Show videos" +msgstr "" + +msgid "Restart this game" +msgstr "" + +msgid "Special pavings" +msgstr "" + +msgid "Incubator or teleporter" +msgstr "" + +msgid "Delete item" +msgstr "" + +msgid "Decorative plants" +msgstr "" + +msgid "Buildings" +msgstr "" + +msgid "Enemy buildings" +msgstr "" + +msgid "Enemy barrier" +msgstr "" + +msgid "Wall or palisade" +msgstr "" + +msgid "Items" +msgstr "" + +msgid "Weapons" +msgstr "" + +msgid "Transport" +msgstr "" + +msgid "Delete figure" +msgstr "" + +msgid "Delete fire" +msgstr "" + +msgid "Starting fire" +msgstr "" + +msgid "Scenery choice" +msgstr "" + +msgid "Music choice" +msgstr "" + +msgid "Available buttons" +msgstr "" + +msgid "Ending conditions" +msgstr "" + +msgid "Quit construction" +msgstr "" + +msgid "Cancel last operation" +msgstr "" + +msgid "Stop" +msgstr "" + +msgid "Go" +msgstr "" + +msgid "Take" +msgstr "" + +msgid "Drop" +msgstr "" + +msgid "Repeat" +msgstr "" + +msgid "Cut down a tree" +msgstr "" + +msgid "Cut down trees" +msgstr "" + +msgid "Carve a rock" +msgstr "" + +msgid "Carve rocks" +msgstr "" + +msgid "Make bunch of flowers" +msgstr "" + +msgid "Make bunches of flowers" +msgstr "" + +msgid "Grow tomatoes" +msgstr "" + +msgid "Eat" +msgstr "" + +msgid "Transform" +msgstr "" + +msgid "Drink" +msgstr "" + +msgid "Blow up" +msgstr "" + +msgid "Prospect for iron" +msgstr "" + +msgid "Extract iron" +msgstr "" + +msgid "Make a Jeep" +msgstr "" + +msgid "Make a time bomb" +msgstr "" + +msgid "Make armour" +msgstr "" + +msgid "Make a helper robot" +msgstr "" + +msgid "Blupi in house" +msgstr "" + +msgid "No more enemies" +msgstr "" + +msgid "Fire out" +msgstr "" + +msgid "Blupi on striped paving stones" +msgstr "" + +msgid "Planks on striped paving stones" +msgstr "" + +msgid "Tomatoes on striped paving stones" +msgstr "" + +msgid "Platinium on striped paving stones" +msgstr "" + +msgid "Robot on striped paving stones" +msgstr "" + +msgid "No music" +msgstr "" + +msgid "Music number 1" +msgstr "" + +msgid "Music number 2" +msgstr "" + +msgid "Music number 3" +msgstr "" + +msgid "Music number 4" +msgstr "" + +msgid "Music number 5" +msgstr "" + +msgid "Music number 6" +msgstr "" + +msgid "Music number 7" +msgstr "" + +msgid "Music number 8" +msgstr "" + +msgid "Music number 9" +msgstr "" + +msgid "Music number 10" +msgstr "" + +msgid "Prairie" +msgstr "" + +msgid "Forest" +msgstr "" + +msgid "Desert" +msgstr "" + +msgid "Forest under snow" +msgstr "" + +msgid "Previous language" +msgstr "" + +msgid "Next language" +msgstr "" + +msgid "Fullscreen" +msgstr "" + +msgid "Windowed" +msgstr "" + +msgid "Use Ogg music" +msgstr "" + +msgid "Use Midi music (original)" +msgstr "" + +msgid "Disable anti-aliasing" +msgstr "" + +msgid "Enable anti-aliasing" +msgstr "" + +msgid "Version" +msgstr "" + +#, c-format +msgid "New version available for download on www.blupi.org (v%s)" +msgstr "" + +msgid "Desktop mode" +msgstr "" + +msgid "Reduce window size" +msgstr "" + +msgid "Legacy mode (640x480)" +msgstr "" + +msgid "Increase window size" +msgstr "" + +msgid "N" +msgstr "" + +msgid "S" +msgstr "" + +msgid "W" +msgstr "" + +msgid "E" +msgstr "" + +msgid "Game paused" +msgstr "" + +msgid "REC" +msgstr "" + +#, c-format +msgid "construction %d, time %d" +msgstr "" + +#, c-format +msgid "mission %d, time %d" +msgstr "" + +#, c-format +msgid "training %d, time %d" +msgstr "" + +msgid "free slot" +msgstr "" + +#, c-format +msgid "Lost if less than %d Blupi" +msgstr "" + +#, c-format +msgid "Impossible to win if less than %d Blupi" +msgstr "" + +msgid "Training number" +msgstr "" + +msgid "Mission number" +msgstr "" + +msgid "Construction number" +msgstr "" + +msgid "Help number" +msgstr "" + +msgid "Easy" +msgstr "" + +msgid "Difficult" +msgstr "" + +msgid "You have failed, try again..." +msgstr "" + +msgid "No, wrong way ..." +msgstr "" + +msgid "Bang, failed again !" +msgstr "" + +msgid "Another mistake..." +msgstr "" + +msgid "No, not that way !" +msgstr "" + +msgid "Well done !" +msgstr "" + +msgid "Yes, great ..." +msgstr "" + +msgid "Very good." +msgstr "" + +msgid "Excellent..." +msgstr "" + +msgid "Mission over..." +msgstr "" + +msgid "Now go on mission." +msgstr "" + +msgid "Very good, success on all missions !" +msgstr "" + +msgid "Last construction resolved !" +msgstr "" + +msgid "" +"Global game\n" +"speed" +msgstr "" + +msgid "" +"Scroll speed\n" +"with mouse" +msgstr "" + +msgid "" +"Sound effect\n" +"volume" +msgstr "" + +msgid "" +"Music\n" +"volume" +msgstr "" + +msgid "" +"Video\n" +"sequences" +msgstr "" + +msgid "No" +msgstr "" + +msgid "Yes" +msgstr "" + +msgid "None" +msgstr "" + +msgid "" +"Interface language\n" +"and sounds" +msgstr "" + +msgid "" +"Select the\n" +"window mode" +msgstr "" + +msgid "" +"Change the\n" +"display mode" +msgstr "" + +msgid "" +"Change the\n" +"window size" +msgstr "" + +msgid "" +"Choose the\n" +"music format" +msgstr "" + +msgid "" +"Change the\n" +"render quality" +msgstr "" + +msgid "Legacy" +msgstr "" + +msgid "Desktop" +msgstr "" + +msgid "Midi" +msgstr "" + +msgid "Ogg" +msgstr "" + +msgid "Anti-aliasing" +msgstr "" + +msgid "Aliasing" +msgstr "" + +msgid "Not available" +msgstr "" + +msgid "You have played Planet Blupi." +msgstr "" + +msgid "We hope you have had as much fun playing the game as we had making it !" +msgstr "" + +msgid "This game uses statically linked free and open-source libraries:" +msgstr "" + +msgid " - argagg (MIT)" +msgstr "" + +msgid " - FFmpeg (LGPLv2.1)" +msgstr "" + +msgid " - GNU/gettext and GNU/libiconv (GPLv3)" +msgstr "" + +msgid " - libasound (LGPLv2.1)" +msgstr "" + +msgid " - libcurl (MIT/X derivate)" +msgstr "" + +msgid " - libogg and libvorbis (own license)" +msgstr "" + +msgid " - libpng (own license)" +msgstr "" + +msgid " - libpulse (LGPLv2.1)" +msgstr "" + +msgid " - libsndfile (LGPLv3)" +msgstr "" + +msgid " - SDL_kitchensink (MIT)" +msgstr "" + +msgid " - SDL2, SDL2_image and SDL2_mixer (zlib license)" +msgstr "" + +msgid " - zlib (own license)" +msgstr "" + +msgid "All licenses are available under share/doc/planetblupi/copyright" +msgstr "" + +msgid "" +"This game is an original creation of Epsitec SA, CH-1400 Yverdon-les-Bains" +msgstr "" + +msgid "http://www.blupi.org info@blupi.org" +msgstr "" + +msgid "Insert CD-Rom Planet Blupi and wait a few seconds..." +msgstr "" + +msgid "Blupi's energy" +msgstr "" + +msgid "Work done" +msgstr "" + +msgid "1|Goal :" +msgstr "" + +msgid "" +"1|Kill all\n" +"1|enemies !" +msgstr "" + +msgid "" +"1|Go on striped\n" +"1|paving stones." +msgstr "" + +msgid "" +"1|Drop planks on striped \n" +"1|paving stones." +msgstr "" + +msgid "" +"1|Drop tomatoes on striped \n" +"1|paving stones." +msgstr "" + +msgid "" +"1|Drop platinium on striped \n" +"1|paving stones." +msgstr "" + +msgid "" +"1|The robot must reach\n" +"1|the striped paving stones." +msgstr "" + +msgid "" +"1|Each Blupi in\n" +"1|his house." +msgstr "" + +msgid "" +"1|Resist until\n" +"1|fire extinction ..." +msgstr "" + +#, c-format +msgid "" +"1|The Blupi population must\n" +"1|be of at least %d Blupi." +msgstr "" + +msgid "Leave Jeep" +msgstr "" + +msgid "Quit" +msgstr "" + +msgid "Impossible" +msgstr "" + +msgid "Inadequate ground" +msgstr "" + +msgid "Occupied ground" +msgstr "" + +msgid "Opposite bank no good" +msgstr "" + +msgid "Bridge finished" +msgstr "" + +msgid "(isolated tower)" +msgstr "" + +msgid "Too close to water" +msgstr "" + +msgid "Already two teleporters" +msgstr "" + +msgid "Not enough energy" +msgstr "" + +msgid "en" +msgstr "" diff --git a/resources/po/pt.po b/resources/po/pt.po new file mode 100644 index 0000000..54a67a0 --- /dev/null +++ b/resources/po/pt.po @@ -0,0 +1,960 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-01-25 23:40+0100\n" +"PO-Revision-Date: 2019-02-17 23:23+0100\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.2.1\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +msgid " - FFmpeg (LGPLv2.1)" +msgstr " - FFmpeg (LGPLv2.1)" + +msgid " - GNU/gettext and GNU/libiconv (GPLv3)" +msgstr "" + +msgid " - SDL2, SDL2_image and SDL2_mixer (zlib license)" +msgstr "" + +msgid " - SDL_kitchensink (MIT)" +msgstr " - SDL_kitchensink (MIT)" + +msgid " - argagg (MIT)" +msgstr " - argagg (MIT)" + +msgid " - libasound (LGPLv2.1)" +msgstr " - libasound (LGPLv2.1)" + +msgid " - libcurl (MIT/X derivate)" +msgstr "" + +msgid " - libogg and libvorbis (own license)" +msgstr "" + +msgid " - libpng (own license)" +msgstr "" + +msgid " - libpulse (LGPLv2.1)" +msgstr " - libpulse (LGPLv2.1)" + +msgid " - libsndfile (LGPLv3)" +msgstr " - libsndfile (LGPLv3)" + +msgid " - zlib (own license)" +msgstr "" + +msgid "(isolated tower)" +msgstr "(torre isolada)" + +msgid "" +"1: Cut down a tree \n" +"2: Build a bridge" +msgstr "" +"1: Cortar planta \n" +"2: Construir uma ponte" + +msgid "" +"1: Cut down a tree \n" +"2: Make a boat" +msgstr "" +"1: Cortar uma planta \n" +"2: Fazer um bote" + +msgid "" +"1: Cut down a tree \n" +"2: Make a palisade" +msgstr "" +"1: Cortar uma planta \n" +"2: Fazer uma barreira" + +msgid "" +"1: Extract iron\n" +"2: Make a Jeep" +msgstr "" +"1: Extrair Ferro\n" +"2: Fazer um Jeep" + +msgid "" +"1: Extract iron\n" +"2: Make a bomb" +msgstr "" +"1: Extrair ferro\n" +"2: Fazer uma bomba" + +msgid "" +"1: Extract iron\n" +"2: Make an armour" +msgstr "" +"1: Extrair ferro\n" +"2: Fazer uma armadura" + +msgid "" +"1: Grow tomatoes\n" +"2: Eat" +msgstr "" +"1: Cultivar tomates\n" +"2: Comer" + +msgid "" +"1: Make a bunch\n" +"2: Transform" +msgstr "" +"1: Fazer um ramo\n" +"2: Transformar" + +msgid "" +"1: Take\n" +"2: Build a bridge" +msgstr "" +"1: Pegar\n" +"2: Construir uma ponte" + +msgid "" +"1: Take\n" +"2: Build palisade" +msgstr "" +"1: Pegar\n" +"2: Construir barreira" + +msgid "" +"1: Take\n" +"2: Make a boat" +msgstr "" +"1: Pegar\n" +"2: Fazer um bote" + +msgid "" +"1: Take\n" +"2: Transform" +msgstr "" +"1: Pegar\n" +"2: Transformar" + +msgid "" +"1|Drop planks on striped \n" +"1|paving stones." +msgstr "" +"1|Largar madeira no \n" +"1|pavimento de pedra." + +msgid "" +"1|Drop platinium on striped \n" +"1|paving stones." +msgstr "" +"1|Largar a platina no \n" +"1|pavimento de pedra." + +msgid "" +"1|Drop tomatoes on striped \n" +"1|paving stones." +msgstr "" +"1|Largar tomates no \n" +"1|pavimento de pedra." + +msgid "" +"1|Each Blupi in\n" +"1|his house." +msgstr "" +"1|Cada Blupi na\n" +"1|sua casa." + +msgid "" +"1|Go on striped\n" +"1|paving stones." +msgstr "" +"1|Ir para\n" +"1| pavimento de pedra." + +msgid "1|Goal :" +msgstr "1|Objetivo :" + +msgid "" +"1|Kill all\n" +"1|enemies !" +msgstr "" +"1|Matar todos os\n" +"1|inimigos !" + +msgid "" +"1|Resist until\n" +"1|fire extinction ..." +msgstr "" +"1|Resistir até\n" +"1|fogo acabar..." + +#, c-format +msgid "" +"1|The Blupi population must\n" +"1|be of at least %d Blupi." +msgstr "" +"1|A população Blupi deve\n" +"1|ser de pelo menos %d \n" +"1|Blupi." + +msgid "" +"1|The robot must reach\n" +"1|the striped paving stones." +msgstr "" +"1|O robo deve atingir\n" +"1|o pavimento de pedra." + +msgid "Aliasing" +msgstr "" + +msgid "All licenses are available under share/doc/planetblupi/copyright" +msgstr "" + +msgid "Already two teleporters" +msgstr "Dois teletransportadores" + +msgid "Another mistake..." +msgstr "Outro erro..." + +msgid "Anti-aliasing" +msgstr "" + +msgid "Armour" +msgstr "Armadura" + +msgid "Available buttons" +msgstr "Botoes disponiveis" + +msgid "Bang, failed again !" +msgstr "Puxa, falhou novamente !" + +msgid "Bank" +msgstr "Margem" + +msgid "Blow up" +msgstr "Explodir" + +msgid "Blupi" +msgstr "Blupi" + +msgid "Blupi in house" +msgstr "Blupi em casa" + +msgid "Blupi on striped paving stones" +msgstr "Blupi no pavimento de pedra" + +msgid "Blupi's energy" +msgstr "Energia do Blupi" + +msgid "Blupi's house" +msgstr "Casa do Blupi" + +msgid "Boat" +msgstr "Bote" + +msgid "Bouncing bomb" +msgstr "Bomba Maluca" + +msgid "Bridge" +msgstr "Ponte" + +msgid "Bridge finished" +msgstr "Ponte terminada" + +msgid "Buildings" +msgstr "Construçãoes" + +msgid "Bulldozer" +msgstr "Escavadora" + +msgid "Bunch of flowers" +msgstr "Ramos de flores" + +msgid "Burnt ground" +msgstr "Terreno queimado" + +msgid "Cancel last operation" +msgstr "Cancelar ultima operação" + +msgid "Carve a rock" +msgstr "Esculpir uma pedra" + +msgid "Carve rocks" +msgstr "Esculpir pedras" + +msgid "" +"Change the\n" +"display mode" +msgstr "" + +msgid "" +"Change the\n" +"render quality" +msgstr "" + +msgid "" +"Change the\n" +"window size" +msgstr "" + +msgid "" +"Choose the\n" +"music format" +msgstr "" + +msgid "Construct this game" +msgstr "Construir este jogo" + +msgid "Construction" +msgstr "Projetar" + +msgid "Construction number" +msgstr "Projeto numero" + +msgid "Continue this game" +msgstr "Continuar este jogo" + +msgid "Cut down a tree" +msgstr "Cortar uma Planta" + +msgid "Cut down trees" +msgstr "Cortar Plantas" + +msgid "Decorative plants" +msgstr "Planta decorativa" + +msgid "Delete figure" +msgstr "Apagar figura" + +msgid "Delete fire" +msgstr "Apagar fogo" + +msgid "Delete item" +msgstr "Apagar item" + +msgid "Demo" +msgstr "Demo" + +msgid "Desert" +msgstr "Deserto" + +msgid "Desktop" +msgstr "" + +msgid "Desktop mode" +msgstr "" + +msgid "Difficult" +msgstr "Dificil" + +msgid "Disable anti-aliasing" +msgstr "" + +msgid "Drink" +msgstr "Beber" + +msgid "Drop" +msgstr "Largar" + +msgid "Dynamite" +msgstr "Dinamite" + +msgid "E" +msgstr "L" + +msgid "Easy" +msgstr "Facil" + +msgid "Eat" +msgstr "Comer" + +msgid "Eggs" +msgstr "Ovos" + +msgid "Electrocutor" +msgstr "Eletrocondutor" + +msgid "Enable anti-aliasing" +msgstr "" + +msgid "Ending conditions" +msgstr "Condições finais" + +msgid "Enemy barrier" +msgstr "Barreira inimiga" + +msgid "Enemy buildings" +msgstr "Construçãoe inimiga" + +msgid "Enemy construction" +msgstr "Construção inimiga" + +msgid "Enemy ground" +msgstr "Terreno Inimigo" + +msgid "Enemy rocket" +msgstr "Foguete inimigo" + +msgid "Excellent..." +msgstr "Excelente..." + +msgid "Extract iron" +msgstr "Extrair ferro" + +msgid "Faster" +msgstr "Mais rapido" + +msgid "Finish" +msgstr "Terminar" + +msgid "Fire" +msgstr "Fogo" + +msgid "Fire out" +msgstr "Resistir até o fogo acabar" + +msgid "Flag" +msgstr "Bandeira" + +msgid "Flowers" +msgstr "Flores" + +msgid "Forest" +msgstr "Floresta" + +msgid "Forest under snow" +msgstr "Floresta debaixo de neve" + +msgid "Fullscreen" +msgstr "" + +msgid "Game paused" +msgstr "Jogo pausado" + +msgid "Garden shed" +msgstr "Casa do jardim" + +msgid "" +"Global game\n" +"speed" +msgstr "Velocidade" + +msgid "Global settings" +msgstr "" + +msgid "Go" +msgstr "Ir" + +msgid "Grow tomatoes" +msgstr "Plantar tomates" + +msgid "Help" +msgstr "Ajuda" + +msgid "Help number" +msgstr "Ajuda numero" + +msgid "Helper robot" +msgstr "Robo Ajudante" + +msgid "Ice" +msgstr "Gelo" + +msgid "Impossible" +msgstr "Impossivel" + +#, c-format +msgid "Impossible to win if less than %d Blupi" +msgstr "Impossivel vencer se tiver menos que %d Blupi" + +msgid "Inadequate ground" +msgstr "Terreno inadequado" + +msgid "Increase volume" +msgstr "Aumentar Volume" + +msgid "Increase window size" +msgstr "" + +msgid "Incubator" +msgstr "Incubadora" + +msgid "Incubator or teleporter" +msgstr "Incubadora ou teletransportador" + +msgid "Inflammable ground" +msgstr "Terreno inflamavel" + +msgid "Insert CD-Rom Planet Blupi and wait a few seconds..." +msgstr "Insira o CD-Rom Planet Blupi e aguarde alguns segundos..." + +msgid "" +"Interface language\n" +"and sounds" +msgstr "" + +msgid "Interrupt" +msgstr "Interromper" + +msgid "Iron" +msgstr "Ferro" + +msgid "Items" +msgstr "Itens" + +msgid "Jeep" +msgstr "Jeep" + +msgid "Laboratory" +msgstr "Laboratorio" + +msgid "Last construction resolved !" +msgstr "Ultima construção resolvida !" + +msgid "Leave Jeep" +msgstr "Deixar o Jeep" + +msgid "Legacy" +msgstr "" + +msgid "Legacy mode (640x480)" +msgstr "" + +#, c-format +msgid "Lost if less than %d Blupi" +msgstr "Perder se tiver menos do que %d Blupi" + +msgid "Make a Jeep" +msgstr "Fazer um Jeep" + +msgid "Make a helper robot" +msgstr "Fazer um robo ajudante" + +msgid "Make a time bomb" +msgstr "Fazer uma bomba" + +msgid "Make armour" +msgstr "Fazer armadura" + +msgid "Make bunch of flowers" +msgstr "Fazer um ramo de flor" + +msgid "Make bunches of flowers" +msgstr "Fazer ramos de flores" + +msgid "Master robot" +msgstr "Robo principal" + +msgid "Medical potion" +msgstr "Remédio" + +msgid "Midi" +msgstr "Midi" + +msgid "Mine" +msgstr "Mina" + +msgid "Miscellaneous ground" +msgstr "Terreno Misto" + +msgid "Mission number" +msgstr "Missao numero" + +msgid "Mission over..." +msgstr "Missao completada..." + +msgid "Missions" +msgstr "Missoes" + +msgid "" +"Music\n" +"volume" +msgstr "" +"Musica\n" +"Volume" + +msgid "Music choice" +msgstr "Musica escolhida" + +msgid "Music number 1" +msgstr "Musica 1" + +msgid "Music number 10" +msgstr "Musica 10" + +msgid "Music number 2" +msgstr "Musica 2" + +msgid "Music number 3" +msgstr "Musica 3" + +msgid "Music number 4" +msgstr "Musica 4" + +msgid "Music number 5" +msgstr "Musica 5" + +msgid "Music number 6" +msgstr "Musica 6" + +msgid "Music number 7" +msgstr "Musica 7" + +msgid "Music number 8" +msgstr "Musica 8" + +msgid "Music number 9" +msgstr "Musica 9" + +msgid "N" +msgstr "N" + +#, c-format +msgid "New version available for download on www.blupi.org (v%s)" +msgstr "" + +msgid "Next game" +msgstr "Jogo seguinte" + +msgid "Next language" +msgstr "" + +msgid "Next page" +msgstr "Pagina seguinte" + +msgid "No" +msgstr "Nao" + +msgid "No more enemies" +msgstr "Matar inimigos" + +msgid "No music" +msgstr "Sem musica" + +msgid "No video" +msgstr "Sem video" + +msgid "No, not that way !" +msgstr "Caminho errado !" + +msgid "No, wrong way ..." +msgstr "Caminho errado ..." + +msgid "None" +msgstr "Nenhum" + +msgid "Normal ground" +msgstr "Terreno normal" + +msgid "Not available" +msgstr "" + +msgid "Not enough energy" +msgstr "" + +msgid "Now go on mission." +msgstr "Agora continue a missao." + +msgid "Occupied ground" +msgstr "Terreno ocupado" + +msgid "Ogg" +msgstr "Ogg" + +msgid "Open another game" +msgstr "Abrir outro jogo" + +msgid "Opposite bank no good" +msgstr "Margem oposta ruim" + +msgid "Palisade" +msgstr "Barreira" + +msgid "Paving stones" +msgstr "Pavimento de pedra" + +msgid "Planet Blupi" +msgstr "Planet Blupi" + +msgid "Planet Blupi -- stop" +msgstr "Planet Blupi -- parar" + +msgid "Planks" +msgstr "Madeiras" + +msgid "Planks on striped paving stones" +msgstr "Madeira no pavimento de pedra" + +msgid "Platinium" +msgstr "Platina" + +msgid "Platinium on striped paving stones" +msgstr "Platina no pavimento de pedra" + +msgid "Play this game" +msgstr "Jogar este jogo" + +msgid "Poison" +msgstr "Veneno" + +msgid "Prairie" +msgstr "Campina" + +msgid "Previous game" +msgstr "Jogo anterior" + +msgid "Previous language" +msgstr "" + +msgid "Previous page" +msgstr "Pagina anterior" + +msgid "Prospect for iron" +msgstr "Procurar por ferro" + +msgid "Protection tower" +msgstr "Torre" + +msgid "Quit" +msgstr "Sair" + +msgid "Quit Planet Blupi" +msgstr "Sair do Planet Blupi" + +msgid "Quit construction" +msgstr "Encerrar projeto" + +msgid "Quit this game" +msgstr "Encerrar este jogo" + +msgid "REC" +msgstr "REC" + +msgid "Reduce volume" +msgstr "Diminuir Volume" + +msgid "Reduce window size" +msgstr "" + +msgid "Repeat" +msgstr "Repetir" + +msgid "Restart this game" +msgstr "Reiniciar este jogo" + +msgid "Robot on striped paving stones" +msgstr "Robo no pavimento de pedra" + +msgid "Rocks" +msgstr "Rochas" + +msgid "S" +msgstr "S" + +msgid "Save" +msgstr "Salvar" + +msgid "Save this game" +msgstr "Salvar este jogo" + +msgid "Scenery choice" +msgstr "Cenario escolhido" + +msgid "" +"Scroll speed\n" +"with mouse" +msgstr "" +"Velocidade de\n" +"Rolagem com mouse" + +msgid "" +"Select the\n" +"window mode" +msgstr "" + +msgid "Settings" +msgstr "Ajustes" + +msgid "Show videos" +msgstr "Mostrar Video" + +msgid "Sick Blupi" +msgstr "Blupi doente" + +msgid "Skill level" +msgstr "Dificuldade" + +msgid "Slower" +msgstr "Mais devagar" + +msgid "" +"Sound effect\n" +"volume" +msgstr "" +"Efeitos de som\n" +"Volume" + +msgid "Special pavings" +msgstr "Pavimento Especial" + +msgid "Spider" +msgstr "Aranha" + +msgid "Starting fire" +msgstr "Iniciar fogo" + +msgid "Sterile ground" +msgstr "Terreno sem vida" + +msgid "Sticky trap" +msgstr "Armadilha pegajosa" + +msgid "Stones" +msgstr "Pedras" + +msgid "Stop" +msgstr "Parar" + +msgid "Striped paving stones" +msgstr "Terreno de pedras" + +msgid "Take" +msgstr "Pegar" + +msgid "Teleporter" +msgstr "Teletransportador" + +msgid "This game is an original creation of Epsitec SA, CH-1400 Yverdon-les-Bains" +msgstr "" + +msgid "This game uses statically linked free and open-source libraries:" +msgstr "" + +msgid "Time bomb" +msgstr "Bomba" + +msgid "Tired Blupi" +msgstr "Blupi cansado" + +msgid "Tomatoes" +msgstr "Tomates" + +msgid "Tomatoes on striped paving stones" +msgstr "Tomates no pavimento de pedra" + +msgid "Too close to water" +msgstr "Muito perto da agua" + +msgid "Training" +msgstr "Treino" + +msgid "Training number" +msgstr "Treino numero" + +msgid "Transform" +msgstr "Transformar" + +msgid "Transport" +msgstr "Transporte" + +msgid "Trapped enemy" +msgstr "Prender inimigos" + +msgid "Tree" +msgstr "Planta" + +msgid "Tree trunks" +msgstr "Tronco de Planta" + +msgid "Use Midi music (original)" +msgstr "" + +msgid "Use Ogg music" +msgstr "" + +msgid "Version" +msgstr "" + +msgid "Very good, success on all missions !" +msgstr "Muito bom, sucesso em todas as missoes !" + +msgid "Very good." +msgstr "Muito bom." + +msgid "" +"Video\n" +"sequences" +msgstr "" +"Video\n" +"Sequencia" + +msgid "Virus" +msgstr "Virus" + +msgid "W" +msgstr "O" + +msgid "Wall" +msgstr "Parede" + +msgid "Wall or palisade" +msgstr "Parede ou Barreira" + +msgid "Water" +msgstr "Agua" + +msgid "We hope you have had as much fun playing the game as we had making it !" +msgstr "Esperamos que você tenha se divertido com este super jogo !" + +msgid "Weapons" +msgstr "Armas" + +msgid "Well done !" +msgstr "Muito bem !" + +msgid "Windowed" +msgstr "" + +msgid "Work done" +msgstr "Trabalho Feito" + +msgid "Workshop" +msgstr "Oficina" + +msgid "Yes" +msgstr "Sim" + +msgid "Yes, great ..." +msgstr "Sim, perfeito ..." + +msgid "You have failed, try again..." +msgstr "Você falhou, tente novamente..." + +msgid "You have played Planet Blupi." +msgstr "Você jogou o Planet Blupi." + +#, c-format +msgid "construction %d, time %d" +msgstr "Projeto %d, tempo %d" + +msgid "en" +msgstr "pt" + +msgid "free slot" +msgstr "pista livre" + +msgid "http://www.blupi.org info@blupi.org" +msgstr "http://www.blupi.org info@blupi.org" + +#, c-format +msgid "mission %d, time %d" +msgstr "missao %d, tempo %d" + +#, c-format +msgid "training %d, time %d" +msgstr "treino %d, tempo %d" diff --git a/resources/po/tr.po b/resources/po/tr.po new file mode 100644 index 0000000..7b3aca4 --- /dev/null +++ b/resources/po/tr.po @@ -0,0 +1,972 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: tr\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-08-08 07:29+0200\n" +"PO-Revision-Date: 2019-02-17 23:26+0100\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: tr_TR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.2.1\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid " - FFmpeg (LGPLv2.1)" +msgstr " - FFmpeg (LGPLv2.1)" + +msgid " - GNU/gettext and GNU/libiconv (GPLv3)" +msgstr " - GNU/gettext ve GNU/libiconv (GPLv3)" + +msgid " - SDL2, SDL2_image and SDL2_mixer (zlib license)" +msgstr " - SDL2, SDL2_image ve SDL2_mixer (zlib lisansı)" + +msgid " - SDL_kitchensink (MIT)" +msgstr " - SDL_kitchensink (MIT)" + +msgid " - argagg (MIT)" +msgstr " - argagg (MIT)" + +msgid " - libasound (LGPLv2.1)" +msgstr " - libasound (LGPLv2.1)" + +msgid " - libcurl (MIT/X derivate)" +msgstr " - libcurl (MIT/X türevi)" + +msgid " - libogg and libvorbis (own license)" +msgstr " - libogg and libvorbis (kendi lisansı)" + +msgid " - libpng (own license)" +msgstr " - libpng (kendi lisansı)" + +msgid " - libpulse (LGPLv2.1)" +msgstr " - libpulse (LGPLv2.1)" + +msgid " - libsndfile (LGPLv3)" +msgstr " - libsndfile (LGPLv3)" + +msgid " - zlib (own license)" +msgstr " - zlib (kendi lisansı)" + +msgid "(isolated tower)" +msgstr "(ayrık kule)" + +msgid "" +"1: Cut down a tree \n" +"2: Build a bridge" +msgstr "" +"1: Bir ağaç kes \n" +"2: Bir köprü inşa et" + +msgid "" +"1: Cut down a tree \n" +"2: Make a boat" +msgstr "" +"1: Bir ağaç kes \n" +"2: Bir kayık yap" + +msgid "" +"1: Cut down a tree \n" +"2: Make a palisade" +msgstr "" +"1: Bir ağaç kes \n" +"2: Kazıklı bir çit yap" + +msgid "" +"1: Extract iron\n" +"2: Make a Jeep" +msgstr "" +"1: Demir çıkar \n" +"2: Bir jip yap" + +msgid "" +"1: Extract iron\n" +"2: Make a bomb" +msgstr "" +"1: Demir çıkar \n" +"2: Bir bomba yap" + +msgid "" +"1: Extract iron\n" +"2: Make an armour" +msgstr "" +"1: Demir çıkar \n" +"2: Bir zırh yap" + +msgid "" +"1: Grow tomatoes\n" +"2: Eat" +msgstr "" +"1: Domates yetiştir \n" +"2: Ye" + +msgid "" +"1: Make a bunch\n" +"2: Transform" +msgstr "" +"1: Bir demet çiçek topla\n" +"2: Dönüştür" + +msgid "" +"1: Take\n" +"2: Build a bridge" +msgstr "" +"1: Al\n" +"2: Bir köprü inşa et" + +msgid "" +"1: Take\n" +"2: Build palisade" +msgstr "" +"1: Al\n" +"2: Kazıklı bir çit yap" + +msgid "" +"1: Take\n" +"2: Make a boat" +msgstr "" +"1: Al\n" +"2: Bir kayık yap" + +msgid "" +"1: Take\n" +"2: Transform" +msgstr "" +"1: Al\n" +"2: Dönüştür" + +msgid "" +"1|Drop planks on striped \n" +"1|paving stones." +msgstr "" +"1|Kalasları çizgili parke \n" +"1|taşına bırak." + +msgid "" +"1|Drop platinium on striped \n" +"1|paving stones." +msgstr "" +"1|Platini çizgili parke \n" +"1|taşına bırak." + +msgid "" +"1|Drop tomatoes on striped \n" +"1|paving stones." +msgstr "" +"1|Domatesleri çizgili parke \n" +"1|taşına bırak." + +msgid "" +"1|Each Blupi in\n" +"1|his house." +msgstr "" +"1|Her Blupi kendi\n" +"1|evinde olmalı." + +msgid "" +"1|Go on striped\n" +"1|paving stones." +msgstr "" +"1|Çizgili parke taşı\n" +"1| üzerinde dur." + +msgid "1|Goal :" +msgstr "1|Hedef :" + +msgid "" +"1|Kill all\n" +"1|enemies !" +msgstr "" +"1|Bütün düşmanları\n" +"1|öldür !" + +msgid "" +"1|Resist until\n" +"1|fire extinction ..." +msgstr "" +"1|Yangın sönene\n" +"1|kadar diren." + +#, c-format +msgid "" +"1|The Blupi population must\n" +"1|be of at least %d Blupi." +msgstr "" +"1|Blupi nüfusu\n" +"1|en az %d olmalı." + +msgid "" +"1|The robot must reach\n" +"1|the striped paving stones." +msgstr "" +"1|Robot çizgili parke\n" +"1|taşına ulaşmalı." + +msgid "Aliasing" +msgstr "Örtüşme" + +msgid "All licenses are available under share/doc/planetblupi/copyright" +msgstr "Bütün lisanslar share/doc/planetblupi/copyright yolu altında mevcut" + +msgid "Already two teleporters" +msgstr "Zaten iki ışınlayıcı var" + +msgid "Another mistake..." +msgstr "Yine olmadı.." + +msgid "Anti-aliasing" +msgstr "Örtüşme önleme" + +msgid "Armour" +msgstr "Zırh" + +msgid "Available buttons" +msgstr "Mevcut butonlar" + +msgid "Bang, failed again !" +msgstr "Güm, yine başaramadık !" + +msgid "Bank" +msgstr "Kıyı" + +msgid "Blow up" +msgstr "Patlat" + +msgid "Blupi" +msgstr "Blupi" + +msgid "Blupi in house" +msgstr "Blupi evde olsun" + +msgid "Blupi on striped paving stones" +msgstr "Blupi çizgili parke taşı üzerinde olsun" + +msgid "Blupi's energy" +msgstr "Blupi'nin enerjisi" + +msgid "Blupi's house" +msgstr "Blupi'nin evi" + +msgid "Boat" +msgstr "Kayık" + +msgid "Bouncing bomb" +msgstr "Zıplayan bomba" + +msgid "Bridge" +msgstr "Köprü" + +msgid "Bridge finished" +msgstr "Köprü tamamlandı" + +msgid "Buildings" +msgstr "Binalar" + +msgid "Bulldozer" +msgstr "Buldozer" + +msgid "Bunch of flowers" +msgstr "Bir demet çiçek" + +msgid "Burnt ground" +msgstr "Yanmış zemin" + +msgid "Cancel last operation" +msgstr "Son işlemi iptal et" + +msgid "Carve a rock" +msgstr "Kayayı kes" + +msgid "Carve rocks" +msgstr "Kayaları kes" + +msgid "" +"Change the\n" +"display mode" +msgstr "" +"Görüntü modunu\n" +"değiştir" + +msgid "" +"Change the\n" +"render quality" +msgstr "" +"Görüntü kalitesini\n" +"değiştir" + +msgid "" +"Change the\n" +"window size" +msgstr "" +"Pencere\n" +"büyüklüğünü\n" +"değiştir" + +msgid "" +"Choose the\n" +"music format" +msgstr "" +"Müzik formatını\n" +"değiştir" + +msgid "Construct this game" +msgstr "Bu oyunu tasarla" + +msgid "Construction" +msgstr "Oyun tasarlama" + +msgid "Construction number" +msgstr "Oyun no" + +msgid "Continue this game" +msgstr "Bu oyuna devam et" + +msgid "Cut down a tree" +msgstr "Ağacı kes" + +msgid "Cut down trees" +msgstr "Ağaçları kes" + +msgid "Decorative plants" +msgstr "Süs bitkiler" + +msgid "Delete figure" +msgstr "Karakteri sil" + +msgid "Delete fire" +msgstr "Yangını sil" + +msgid "Delete item" +msgstr "Öğeyi sil" + +msgid "Demo" +msgstr "Demo" + +msgid "Desert" +msgstr "Çöl" + +msgid "Desktop" +msgstr "Masaüstü" + +msgid "Desktop mode" +msgstr "Masaüstü modu" + +msgid "Difficult" +msgstr "Zor" + +msgid "Disable anti-aliasing" +msgstr "Örtüşme önlemeyi devre dışı bırak" + +msgid "Drink" +msgstr "İç" + +msgid "Drop" +msgstr "Bırak" + +msgid "Dynamite" +msgstr "Dinamit" + +msgid "E" +msgstr "D" + +msgid "Easy" +msgstr "Kolay" + +msgid "Eat" +msgstr "Ye" + +msgid "Eggs" +msgstr "Yumurtalar" + +msgid "Electrocutor" +msgstr "Elektrikçarpar" + +msgid "Enable anti-aliasing" +msgstr "Örtüşme önlemeyi etkinleştir" + +msgid "Ending conditions" +msgstr "Bitirme koşulları" + +msgid "Enemy barrier" +msgstr "Düşman barikatı" + +msgid "Enemy buildings" +msgstr "Düşman binaları" + +msgid "Enemy construction" +msgstr "Düşman binası" + +msgid "Enemy ground" +msgstr "Düşman arazisi" + +msgid "Enemy rocket" +msgstr "Düşman roketi" + +msgid "Excellent..." +msgstr "Mükemmel." + +msgid "Extract iron" +msgstr "Demir çıkar" + +msgid "Faster" +msgstr "Daha hızlı" + +msgid "Finish" +msgstr "Bitir" + +msgid "Fire" +msgstr "Yangın" + +msgid "Fire out" +msgstr "Yangın sönsün" + +msgid "Flag" +msgstr "Bayrak" + +msgid "Flowers" +msgstr "Çiçekler" + +msgid "Forest" +msgstr "Orman" + +msgid "Forest under snow" +msgstr "Kar altında orman" + +msgid "Fullscreen" +msgstr "Tam ekran" + +msgid "Game paused" +msgstr "Oyun durduruldu" + +msgid "Garden shed" +msgstr "Bahçe kulübesi" + +msgid "" +"Global game\n" +"speed" +msgstr "" +"Genel oyun\n" +"hızı" + +msgid "Global settings" +msgstr "Genel ayarlar" + +msgid "Go" +msgstr "Git" + +msgid "Grow tomatoes" +msgstr "Domates yetiştir" + +msgid "Help" +msgstr "Yardım" + +msgid "Help number" +msgstr "Yardım no" + +msgid "Helper robot" +msgstr "Yardımcı robot" + +msgid "Ice" +msgstr "Buz" + +msgid "Impossible" +msgstr "İmkansız" + +#, c-format +msgid "Impossible to win if less than %d Blupi" +msgstr "Eğer nüfus %d Blupi'den azsa kazanmak imkansız" + +msgid "Inadequate ground" +msgstr "Arazi uygun edğil" + +msgid "Increase volume" +msgstr "Ses seviyesini arttır" + +msgid "Increase window size" +msgstr "Pencere büyüklüğünü arttır" + +msgid "Incubator" +msgstr "İnkübatör" + +msgid "Incubator or teleporter" +msgstr "İnkübatör veya ışınlayıcı" + +msgid "Inflammable ground" +msgstr "Alev alabilen zemin" + +msgid "Insert CD-Rom Planet Blupi and wait a few seconds..." +msgstr "Planet Blupi CD-Rom'unu takın ve birkaç saniye bekleyin..." + +msgid "" +"Interface language\n" +"and sounds" +msgstr "" +"Arayüz dili\n" +"ve sesleri" + +msgid "Interrupt" +msgstr "Oyunu yarıda kes" + +msgid "Iron" +msgstr "Demir" + +msgid "Items" +msgstr "Öğeler" + +msgid "Jeep" +msgstr "Jip" + +msgid "Laboratory" +msgstr "Laboratuvar" + +msgid "Last construction resolved !" +msgstr "Son oyun çözüldü !" + +msgid "Leave Jeep" +msgstr "Jipten ayrıl" + +msgid "Legacy" +msgstr "Eski" + +msgid "Legacy mode (640x480)" +msgstr "Eski mod (640x480)" + +#, c-format +msgid "Lost if less than %d Blupi" +msgstr "Nüfus %d Blupi'den azsa kaybedilir" + +msgid "Make a Jeep" +msgstr "Bir jip yap" + +msgid "Make a helper robot" +msgstr "Yardımcı bir robot yap" + +msgid "Make a time bomb" +msgstr "Saatli bir bomba yap" + +msgid "Make armour" +msgstr "Zırh yap" + +msgid "Make bunch of flowers" +msgstr "Bir demet çiçek topla" + +msgid "Make bunches of flowers" +msgstr "Demetlerce çiçek topla" + +msgid "Master robot" +msgstr "Baş robot" + +msgid "Medical potion" +msgstr "Tıbbi ilaç" + +msgid "Midi" +msgstr "Midi" + +msgid "Mine" +msgstr "Maden" + +msgid "Miscellaneous ground" +msgstr "Karışık zemin" + +msgid "Mission number" +msgstr "Görev no" + +msgid "Mission over..." +msgstr "Görev tamamlandı." + +msgid "Missions" +msgstr "Görevler" + +msgid "" +"Music\n" +"volume" +msgstr "Müzik seviyesi" + +msgid "Music choice" +msgstr "Müzik seçimi" + +msgid "Music number 1" +msgstr "Müzik no 1" + +msgid "Music number 10" +msgstr "Müzik no 10" + +msgid "Music number 2" +msgstr "Müzik no 2" + +msgid "Music number 3" +msgstr "Müzik no 3" + +msgid "Music number 4" +msgstr "Müzik no 4" + +msgid "Music number 5" +msgstr "Müzik no 5" + +msgid "Music number 6" +msgstr "Müzik no 6" + +msgid "Music number 7" +msgstr "Müzik no 7" + +msgid "Music number 8" +msgstr "Müzik no 8" + +msgid "Music number 9" +msgstr "Müzik no 9" + +msgid "N" +msgstr "K" + +#, c-format +msgid "New version available for download on www.blupi.org (v%s)" +msgstr "Oyunun yeni bir versiyonu mevcut www.blupi.org (v%s)" + +msgid "Next game" +msgstr "Sonraki oyun" + +msgid "Next language" +msgstr "Sonraki dil" + +msgid "Next page" +msgstr "Sonraki sayfa" + +msgid "No" +msgstr "Hayır" + +msgid "No more enemies" +msgstr "Düşman kalmasın" + +msgid "No music" +msgstr "Müzik yok" + +msgid "No video" +msgstr "Video yok" + +msgid "No, not that way !" +msgstr "Hayır, olamaz !" + +msgid "No, wrong way ..." +msgstr "Bu şekilde değil..." + +msgid "None" +msgstr "Yok" + +msgid "Normal ground" +msgstr "Normal zemin" + +msgid "Not available" +msgstr "Mevcut değil" + +msgid "Not enough energy" +msgstr "Yetersiz enerji" + +msgid "Now go on mission." +msgstr "Şimdi göreve devam et." + +msgid "Occupied ground" +msgstr "Dolu alan" + +msgid "Ogg" +msgstr "Ogg" + +msgid "Open another game" +msgstr "Başka bir oyun aç" + +msgid "Opposite bank no good" +msgstr "Karşı kıyı uygun değil" + +msgid "Palisade" +msgstr "Kazıklı çit" + +msgid "Paving stones" +msgstr "Parke taşı" + +msgid "Planet Blupi" +msgstr "Planet Blupi" + +msgid "Planet Blupi -- stop" +msgstr "Planet Blupi -- dur" + +msgid "Planks" +msgstr "Kalaslar" + +msgid "Planks on striped paving stones" +msgstr "Kalaslar çizgili parke taşı üzerinde olsun" + +msgid "Platinium" +msgstr "Platin" + +msgid "Platinium on striped paving stones" +msgstr "Platin çizgili parke taşı üzerinde olsun" + +msgid "Play this game" +msgstr "Bu oyunu oyna" + +msgid "Poison" +msgstr "Zehir" + +msgid "Prairie" +msgstr "Bozkır" + +msgid "Previous game" +msgstr "Önceki oyun" + +msgid "Previous language" +msgstr "Önceki dil" + +msgid "Previous page" +msgstr "Önceki sayfa" + +msgid "Prospect for iron" +msgstr "Demir ara" + +msgid "Protection tower" +msgstr "Koruma kulesi" + +msgid "Quit" +msgstr "Çık" + +msgid "Quit Planet Blupi" +msgstr "Planet Blupi'den çık" + +msgid "Quit construction" +msgstr "Oyundan çık" + +msgid "Quit this game" +msgstr "Bu oyundan çık" + +msgid "REC" +msgstr "REC" + +msgid "Reduce volume" +msgstr "Ses seviyesini azalt" + +msgid "Reduce window size" +msgstr "Pencere büyüklüğünü azalt" + +msgid "Repeat" +msgstr "Tekrar et" + +msgid "Restart this game" +msgstr "Bu oyunu tekrar başlat" + +msgid "Robot on striped paving stones" +msgstr "Robot çizgili parke taşı üzerinde olsun" + +msgid "Rocks" +msgstr "Kayalar" + +msgid "S" +msgstr "G" + +msgid "Save" +msgstr "Kaydet" + +msgid "Save this game" +msgstr "Bu oyunu kaydet" + +msgid "Scenery choice" +msgstr "Manzara seçimi" + +msgid "" +"Scroll speed\n" +"with mouse" +msgstr "" +"Fare kaydırma\n" +"hızı" + +msgid "" +"Select the\n" +"window mode" +msgstr "" +"Pencere\n" +"modu seç" + +msgid "Settings" +msgstr "Ayarlar" + +msgid "Show videos" +msgstr "Videoları göster" + +msgid "Sick Blupi" +msgstr "Hasta Blupi" + +msgid "Skill level" +msgstr "Beceri düzeyi" + +msgid "Slower" +msgstr "Daha yavaş" + +msgid "" +"Sound effect\n" +"volume" +msgstr "" +"Ses efekti\n" +"seviyesi" + +msgid "Special pavings" +msgstr "Özel kaplamalar" + +msgid "Spider" +msgstr "Örümcek" + +msgid "Starting fire" +msgstr "Yangın başlatma" + +msgid "Sterile ground" +msgstr "Verimsiz toprak" + +msgid "Sticky trap" +msgstr "Yapışkan tuzak" + +msgid "Stones" +msgstr "Taşlar" + +msgid "Stop" +msgstr "Dur" + +msgid "Striped paving stones" +msgstr "Çizgili parke taşı" + +msgid "Take" +msgstr "Al" + +msgid "Teleporter" +msgstr "Işınlayıcı" + +msgid "This game is an original creation of Epsitec SA, CH-1400 Yverdon-les-Bains" +msgstr "Bu oyun Epsitec SA, CH-1400 Yverdon-les-Bains'in orijinal ürünüdür" + +msgid "This game uses statically linked free and open-source libraries:" +msgstr "Bu oyun ücretsiz ve açık kaynak kodlu kütüphaneler kullanmaktadır:" + +msgid "Time bomb" +msgstr "Saatli bomba" + +msgid "Tired Blupi" +msgstr "Bitkin Blupi" + +msgid "Tomatoes" +msgstr "Domatesler" + +msgid "Tomatoes on striped paving stones" +msgstr "Domatesler çizgili parke taşı üzerinde olsun" + +msgid "Too close to water" +msgstr "Suya çok yakın" + +msgid "Training" +msgstr "Eğitim" + +msgid "Training number" +msgstr "Eğitim no" + +msgid "Transform" +msgstr "Dönüştür" + +msgid "Transport" +msgstr "Ulaşım" + +msgid "Trapped enemy" +msgstr "Tuzağa düşmüş düşman" + +msgid "Tree" +msgstr "Ağaç" + +msgid "Tree trunks" +msgstr "Ağaç gövdeleri" + +msgid "Use Midi music (original)" +msgstr "Midi müzik kullan (orijinal)" + +msgid "Use Ogg music" +msgstr "Ogg müzik kullan" + +msgid "Version" +msgstr "Versiyon" + +msgid "Very good, success on all missions !" +msgstr "Bütün görevler başarılı !" + +msgid "Very good." +msgstr "Çok iyi." + +msgid "" +"Video\n" +"sequences" +msgstr "" +"Video\n" +"kesitleri" + +msgid "Virus" +msgstr "Virüs" + +msgid "W" +msgstr "B" + +msgid "Wall" +msgstr "Duvar" + +msgid "Wall or palisade" +msgstr "Duvar veya çit" + +msgid "Water" +msgstr "Su" + +msgid "We hope you have had as much fun playing the game as we had making it !" +msgstr "Umarız ki oyunu oynamaktan, bizim oyunu yaptığımız kadar, eğlenmişsinizdir !" + +msgid "Weapons" +msgstr "Silahlar" + +msgid "Well done !" +msgstr "Aferin !" + +msgid "Windowed" +msgstr "Pencere görünümü" + +msgid "Work done" +msgstr "Yapılan iş" + +msgid "Workshop" +msgstr "Atölye" + +msgid "Yes" +msgstr "Evet" + +msgid "Yes, great ..." +msgstr "Evet, harika." + +msgid "You have failed, try again..." +msgstr "Kaybettin, tekrar dene..." + +msgid "You have played Planet Blupi." +msgstr "Planet Blupi'yi oynadınız." + +#, c-format +msgid "construction %d, time %d" +msgstr "oyun %d, zaman %d" + +msgid "en" +msgstr "tr" + +msgid "free slot" +msgstr "boş yer" + +msgid "http://www.blupi.org info@blupi.org" +msgstr "http://www.blupi.org info@blupi.org" + +#, c-format +msgid "mission %d, time %d" +msgstr "görev %d, zaman %d" + +#, c-format +msgid "training %d, time %d" +msgstr "eğitim %d, zaman %d" diff --git a/resources/sound/de/sound002.wav b/resources/sound/de/sound002.wav new file mode 100644 index 0000000..a73bac3 Binary files /dev/null and b/resources/sound/de/sound002.wav differ diff --git a/resources/sound/de/sound003.wav b/resources/sound/de/sound003.wav new file mode 100644 index 0000000..8cfecd1 Binary files /dev/null and b/resources/sound/de/sound003.wav differ diff --git a/resources/sound/de/sound004.wav b/resources/sound/de/sound004.wav new file mode 100644 index 0000000..d843a7b Binary files /dev/null and b/resources/sound/de/sound004.wav differ diff --git a/resources/sound/de/sound005.wav b/resources/sound/de/sound005.wav new file mode 100644 index 0000000..a7c1f39 Binary files /dev/null and b/resources/sound/de/sound005.wav differ diff --git a/resources/sound/de/sound006.wav b/resources/sound/de/sound006.wav new file mode 100644 index 0000000..f8fdde1 Binary files /dev/null and b/resources/sound/de/sound006.wav differ diff --git a/resources/sound/de/sound007.wav b/resources/sound/de/sound007.wav new file mode 100644 index 0000000..7e78255 Binary files /dev/null and b/resources/sound/de/sound007.wav differ diff --git a/resources/sound/de/sound008.wav b/resources/sound/de/sound008.wav new file mode 100644 index 0000000..709c7d2 Binary files /dev/null and b/resources/sound/de/sound008.wav differ diff --git a/resources/sound/de/sound009.wav b/resources/sound/de/sound009.wav new file mode 100644 index 0000000..7fa4d80 Binary files /dev/null and b/resources/sound/de/sound009.wav differ diff --git a/resources/sound/de/sound010.wav b/resources/sound/de/sound010.wav new file mode 100644 index 0000000..8dc3ccd Binary files /dev/null and b/resources/sound/de/sound010.wav differ diff --git a/resources/sound/de/sound014.wav b/resources/sound/de/sound014.wav new file mode 100644 index 0000000..244205f Binary files /dev/null and b/resources/sound/de/sound014.wav differ diff --git a/resources/sound/de/sound017.wav b/resources/sound/de/sound017.wav new file mode 100644 index 0000000..d0c79fb Binary files /dev/null and b/resources/sound/de/sound017.wav differ diff --git a/resources/sound/de/sound018.wav b/resources/sound/de/sound018.wav new file mode 100644 index 0000000..0808476 Binary files /dev/null and b/resources/sound/de/sound018.wav differ diff --git a/resources/sound/de/sound019.wav b/resources/sound/de/sound019.wav new file mode 100644 index 0000000..8ee23a4 Binary files /dev/null and b/resources/sound/de/sound019.wav differ diff --git a/resources/sound/de/sound027.wav b/resources/sound/de/sound027.wav new file mode 100644 index 0000000..89b24e2 Binary files /dev/null and b/resources/sound/de/sound027.wav differ diff --git a/resources/sound/de/sound033.wav b/resources/sound/de/sound033.wav new file mode 100644 index 0000000..6f27d2b Binary files /dev/null and b/resources/sound/de/sound033.wav differ diff --git a/resources/sound/de/sound037.wav b/resources/sound/de/sound037.wav new file mode 100644 index 0000000..17a00b2 Binary files /dev/null and b/resources/sound/de/sound037.wav differ diff --git a/resources/sound/de/sound056.wav b/resources/sound/de/sound056.wav new file mode 100644 index 0000000..d01f352 Binary files /dev/null and b/resources/sound/de/sound056.wav differ diff --git a/resources/sound/de/sound057.wav b/resources/sound/de/sound057.wav new file mode 100644 index 0000000..ca50c05 Binary files /dev/null and b/resources/sound/de/sound057.wav differ diff --git a/resources/sound/de/sound058.wav b/resources/sound/de/sound058.wav new file mode 100644 index 0000000..1fdacfe Binary files /dev/null and b/resources/sound/de/sound058.wav differ diff --git a/resources/sound/de/sound059.wav b/resources/sound/de/sound059.wav new file mode 100644 index 0000000..6a5aab0 Binary files /dev/null and b/resources/sound/de/sound059.wav differ diff --git a/resources/sound/de/sound060.wav b/resources/sound/de/sound060.wav new file mode 100644 index 0000000..fab8907 Binary files /dev/null and b/resources/sound/de/sound060.wav differ diff --git a/resources/sound/de/sound061.wav b/resources/sound/de/sound061.wav new file mode 100644 index 0000000..244171a Binary files /dev/null and b/resources/sound/de/sound061.wav differ diff --git a/resources/sound/de/sound062.wav b/resources/sound/de/sound062.wav new file mode 100644 index 0000000..cffcaf4 Binary files /dev/null and b/resources/sound/de/sound062.wav differ diff --git a/resources/sound/de/sound063.wav b/resources/sound/de/sound063.wav new file mode 100644 index 0000000..0b3794d Binary files /dev/null and b/resources/sound/de/sound063.wav differ diff --git a/resources/sound/de/sound064.wav b/resources/sound/de/sound064.wav new file mode 100644 index 0000000..098c0f4 Binary files /dev/null and b/resources/sound/de/sound064.wav differ diff --git a/resources/sound/de/sound065.wav b/resources/sound/de/sound065.wav new file mode 100644 index 0000000..f065191 Binary files /dev/null and b/resources/sound/de/sound065.wav differ diff --git a/resources/sound/de/sound066.wav b/resources/sound/de/sound066.wav new file mode 100644 index 0000000..951d7f3 Binary files /dev/null and b/resources/sound/de/sound066.wav differ diff --git a/resources/sound/de/sound067.wav b/resources/sound/de/sound067.wav new file mode 100644 index 0000000..5148c6f Binary files /dev/null and b/resources/sound/de/sound067.wav differ diff --git a/resources/sound/de/sound068.wav b/resources/sound/de/sound068.wav new file mode 100644 index 0000000..753195a Binary files /dev/null and b/resources/sound/de/sound068.wav differ diff --git a/resources/sound/de/sound069.wav b/resources/sound/de/sound069.wav new file mode 100644 index 0000000..246f73a Binary files /dev/null and b/resources/sound/de/sound069.wav differ diff --git a/resources/sound/de/sound070.wav b/resources/sound/de/sound070.wav new file mode 100644 index 0000000..02e815f Binary files /dev/null and b/resources/sound/de/sound070.wav differ diff --git a/resources/sound/de/sound071.wav b/resources/sound/de/sound071.wav new file mode 100644 index 0000000..709c7d2 Binary files /dev/null and b/resources/sound/de/sound071.wav differ diff --git a/resources/sound/de/sound072.wav b/resources/sound/de/sound072.wav new file mode 100644 index 0000000..7fa4d80 Binary files /dev/null and b/resources/sound/de/sound072.wav differ diff --git a/resources/sound/de/sound073.wav b/resources/sound/de/sound073.wav new file mode 100644 index 0000000..8dc3ccd Binary files /dev/null and b/resources/sound/de/sound073.wav differ diff --git a/resources/sound/en/sound000.wav b/resources/sound/en/sound000.wav new file mode 100644 index 0000000..388fed1 Binary files /dev/null and b/resources/sound/en/sound000.wav differ diff --git a/resources/sound/en/sound001.wav b/resources/sound/en/sound001.wav new file mode 100644 index 0000000..b65562f Binary files /dev/null and b/resources/sound/en/sound001.wav differ diff --git a/resources/sound/en/sound002.wav b/resources/sound/en/sound002.wav new file mode 100644 index 0000000..3c5aad6 Binary files /dev/null and b/resources/sound/en/sound002.wav differ diff --git a/resources/sound/en/sound003.wav b/resources/sound/en/sound003.wav new file mode 100644 index 0000000..8bc7cf9 Binary files /dev/null and b/resources/sound/en/sound003.wav differ diff --git a/resources/sound/en/sound004.wav b/resources/sound/en/sound004.wav new file mode 100644 index 0000000..9966510 Binary files /dev/null and b/resources/sound/en/sound004.wav differ diff --git a/resources/sound/en/sound005.wav b/resources/sound/en/sound005.wav new file mode 100644 index 0000000..bde8aad Binary files /dev/null and b/resources/sound/en/sound005.wav differ diff --git a/resources/sound/en/sound006.wav b/resources/sound/en/sound006.wav new file mode 100644 index 0000000..056c74d Binary files /dev/null and b/resources/sound/en/sound006.wav differ diff --git a/resources/sound/en/sound007.wav b/resources/sound/en/sound007.wav new file mode 100644 index 0000000..10a0ee0 Binary files /dev/null and b/resources/sound/en/sound007.wav differ diff --git a/resources/sound/en/sound008.wav b/resources/sound/en/sound008.wav new file mode 100644 index 0000000..9640b2c Binary files /dev/null and b/resources/sound/en/sound008.wav differ diff --git a/resources/sound/en/sound009.wav b/resources/sound/en/sound009.wav new file mode 100644 index 0000000..62a0fd5 Binary files /dev/null and b/resources/sound/en/sound009.wav differ diff --git a/resources/sound/en/sound010.wav b/resources/sound/en/sound010.wav new file mode 100644 index 0000000..1f581e4 Binary files /dev/null and b/resources/sound/en/sound010.wav differ diff --git a/resources/sound/en/sound011.wav b/resources/sound/en/sound011.wav new file mode 100644 index 0000000..eb3b515 Binary files /dev/null and b/resources/sound/en/sound011.wav differ diff --git a/resources/sound/en/sound012.wav b/resources/sound/en/sound012.wav new file mode 100644 index 0000000..eb11895 Binary files /dev/null and b/resources/sound/en/sound012.wav differ diff --git a/resources/sound/en/sound013.wav b/resources/sound/en/sound013.wav new file mode 100644 index 0000000..95bc99d Binary files /dev/null and b/resources/sound/en/sound013.wav differ diff --git a/resources/sound/en/sound014.wav b/resources/sound/en/sound014.wav new file mode 100644 index 0000000..36ec77a Binary files /dev/null and b/resources/sound/en/sound014.wav differ diff --git a/resources/sound/en/sound015.wav b/resources/sound/en/sound015.wav new file mode 100644 index 0000000..c59d92e Binary files /dev/null and b/resources/sound/en/sound015.wav differ diff --git a/resources/sound/en/sound016.wav b/resources/sound/en/sound016.wav new file mode 100644 index 0000000..46b2e6d Binary files /dev/null and b/resources/sound/en/sound016.wav differ diff --git a/resources/sound/en/sound017.wav b/resources/sound/en/sound017.wav new file mode 100644 index 0000000..35dbb72 Binary files /dev/null and b/resources/sound/en/sound017.wav differ diff --git a/resources/sound/en/sound018.wav b/resources/sound/en/sound018.wav new file mode 100644 index 0000000..4e575ea Binary files /dev/null and b/resources/sound/en/sound018.wav differ diff --git a/resources/sound/en/sound019.wav b/resources/sound/en/sound019.wav new file mode 100644 index 0000000..7a4332b Binary files /dev/null and b/resources/sound/en/sound019.wav differ diff --git a/resources/sound/en/sound020.wav b/resources/sound/en/sound020.wav new file mode 100644 index 0000000..ede68b5 Binary files /dev/null and b/resources/sound/en/sound020.wav differ diff --git a/resources/sound/en/sound021.wav b/resources/sound/en/sound021.wav new file mode 100644 index 0000000..0b4b5f2 Binary files /dev/null and b/resources/sound/en/sound021.wav differ diff --git a/resources/sound/en/sound022.wav b/resources/sound/en/sound022.wav new file mode 100644 index 0000000..d95d9e6 Binary files /dev/null and b/resources/sound/en/sound022.wav differ diff --git a/resources/sound/en/sound023.wav b/resources/sound/en/sound023.wav new file mode 100644 index 0000000..eb0ae91 Binary files /dev/null and b/resources/sound/en/sound023.wav differ diff --git a/resources/sound/en/sound024.wav b/resources/sound/en/sound024.wav new file mode 100644 index 0000000..a1711ac Binary files /dev/null and b/resources/sound/en/sound024.wav differ diff --git a/resources/sound/en/sound025.wav b/resources/sound/en/sound025.wav new file mode 100644 index 0000000..91783eb Binary files /dev/null and b/resources/sound/en/sound025.wav differ diff --git a/resources/sound/en/sound026.wav b/resources/sound/en/sound026.wav new file mode 100644 index 0000000..87d7de0 Binary files /dev/null and b/resources/sound/en/sound026.wav differ diff --git a/resources/sound/en/sound027.wav b/resources/sound/en/sound027.wav new file mode 100644 index 0000000..e32f9d3 Binary files /dev/null and b/resources/sound/en/sound027.wav differ diff --git a/resources/sound/en/sound028.wav b/resources/sound/en/sound028.wav new file mode 100644 index 0000000..ad23143 Binary files /dev/null and b/resources/sound/en/sound028.wav differ diff --git a/resources/sound/en/sound029.wav b/resources/sound/en/sound029.wav new file mode 100644 index 0000000..0d15ba9 Binary files /dev/null and b/resources/sound/en/sound029.wav differ diff --git a/resources/sound/en/sound030.wav b/resources/sound/en/sound030.wav new file mode 100644 index 0000000..48fb3f8 Binary files /dev/null and b/resources/sound/en/sound030.wav differ diff --git a/resources/sound/en/sound031.wav b/resources/sound/en/sound031.wav new file mode 100644 index 0000000..9210385 Binary files /dev/null and b/resources/sound/en/sound031.wav differ diff --git a/resources/sound/en/sound032.wav b/resources/sound/en/sound032.wav new file mode 100644 index 0000000..a5e3c39 Binary files /dev/null and b/resources/sound/en/sound032.wav differ diff --git a/resources/sound/en/sound033.wav b/resources/sound/en/sound033.wav new file mode 100644 index 0000000..109ec7b Binary files /dev/null and b/resources/sound/en/sound033.wav differ diff --git a/resources/sound/en/sound034.wav b/resources/sound/en/sound034.wav new file mode 100644 index 0000000..421d038 Binary files /dev/null and b/resources/sound/en/sound034.wav differ diff --git a/resources/sound/en/sound035.wav b/resources/sound/en/sound035.wav new file mode 100644 index 0000000..eb369cb Binary files /dev/null and b/resources/sound/en/sound035.wav differ diff --git a/resources/sound/en/sound036.wav b/resources/sound/en/sound036.wav new file mode 100644 index 0000000..756f298 Binary files /dev/null and b/resources/sound/en/sound036.wav differ diff --git a/resources/sound/en/sound037.wav b/resources/sound/en/sound037.wav new file mode 100644 index 0000000..703331d Binary files /dev/null and b/resources/sound/en/sound037.wav differ diff --git a/resources/sound/en/sound038.wav b/resources/sound/en/sound038.wav new file mode 100644 index 0000000..76af3f6 Binary files /dev/null and b/resources/sound/en/sound038.wav differ diff --git a/resources/sound/en/sound039.wav b/resources/sound/en/sound039.wav new file mode 100644 index 0000000..314f663 Binary files /dev/null and b/resources/sound/en/sound039.wav differ diff --git a/resources/sound/en/sound040.wav b/resources/sound/en/sound040.wav new file mode 100644 index 0000000..5d0696d Binary files /dev/null and b/resources/sound/en/sound040.wav differ diff --git a/resources/sound/en/sound041.wav b/resources/sound/en/sound041.wav new file mode 100644 index 0000000..6bbc067 Binary files /dev/null and b/resources/sound/en/sound041.wav differ diff --git a/resources/sound/en/sound042.wav b/resources/sound/en/sound042.wav new file mode 100644 index 0000000..bee6ba7 Binary files /dev/null and b/resources/sound/en/sound042.wav differ diff --git a/resources/sound/en/sound043.wav b/resources/sound/en/sound043.wav new file mode 100644 index 0000000..ddccd52 Binary files /dev/null and b/resources/sound/en/sound043.wav differ diff --git a/resources/sound/en/sound044.wav b/resources/sound/en/sound044.wav new file mode 100644 index 0000000..ea78d0d Binary files /dev/null and b/resources/sound/en/sound044.wav differ diff --git a/resources/sound/en/sound045.wav b/resources/sound/en/sound045.wav new file mode 100644 index 0000000..c86c1ad Binary files /dev/null and b/resources/sound/en/sound045.wav differ diff --git a/resources/sound/en/sound046.wav b/resources/sound/en/sound046.wav new file mode 100644 index 0000000..cdabb5d Binary files /dev/null and b/resources/sound/en/sound046.wav differ diff --git a/resources/sound/en/sound047.wav b/resources/sound/en/sound047.wav new file mode 100644 index 0000000..4887327 Binary files /dev/null and b/resources/sound/en/sound047.wav differ diff --git a/resources/sound/en/sound048.wav b/resources/sound/en/sound048.wav new file mode 100644 index 0000000..e9ad25e Binary files /dev/null and b/resources/sound/en/sound048.wav differ diff --git a/resources/sound/en/sound049.wav b/resources/sound/en/sound049.wav new file mode 100644 index 0000000..6176140 Binary files /dev/null and b/resources/sound/en/sound049.wav differ diff --git a/resources/sound/en/sound050.wav b/resources/sound/en/sound050.wav new file mode 100644 index 0000000..d0af514 Binary files /dev/null and b/resources/sound/en/sound050.wav differ diff --git a/resources/sound/en/sound051.wav b/resources/sound/en/sound051.wav new file mode 100644 index 0000000..3152eec Binary files /dev/null and b/resources/sound/en/sound051.wav differ diff --git a/resources/sound/en/sound052.wav b/resources/sound/en/sound052.wav new file mode 100644 index 0000000..ecc79a6 Binary files /dev/null and b/resources/sound/en/sound052.wav differ diff --git a/resources/sound/en/sound053.wav b/resources/sound/en/sound053.wav new file mode 100644 index 0000000..4eceb53 Binary files /dev/null and b/resources/sound/en/sound053.wav differ diff --git a/resources/sound/en/sound054.wav b/resources/sound/en/sound054.wav new file mode 100644 index 0000000..6cc3ab3 Binary files /dev/null and b/resources/sound/en/sound054.wav differ diff --git a/resources/sound/en/sound055.wav b/resources/sound/en/sound055.wav new file mode 100644 index 0000000..3633c2f Binary files /dev/null and b/resources/sound/en/sound055.wav differ diff --git a/resources/sound/en/sound056.wav b/resources/sound/en/sound056.wav new file mode 100644 index 0000000..e96e4b0 Binary files /dev/null and b/resources/sound/en/sound056.wav differ diff --git a/resources/sound/en/sound057.wav b/resources/sound/en/sound057.wav new file mode 100644 index 0000000..23b3630 Binary files /dev/null and b/resources/sound/en/sound057.wav differ diff --git a/resources/sound/en/sound058.wav b/resources/sound/en/sound058.wav new file mode 100644 index 0000000..8ac9aa1 Binary files /dev/null and b/resources/sound/en/sound058.wav differ diff --git a/resources/sound/en/sound059.wav b/resources/sound/en/sound059.wav new file mode 100644 index 0000000..d347233 Binary files /dev/null and b/resources/sound/en/sound059.wav differ diff --git a/resources/sound/en/sound060.wav b/resources/sound/en/sound060.wav new file mode 100644 index 0000000..dbb2a75 Binary files /dev/null and b/resources/sound/en/sound060.wav differ diff --git a/resources/sound/en/sound061.wav b/resources/sound/en/sound061.wav new file mode 100644 index 0000000..531c7c3 Binary files /dev/null and b/resources/sound/en/sound061.wav differ diff --git a/resources/sound/en/sound062.wav b/resources/sound/en/sound062.wav new file mode 100644 index 0000000..2aa3173 Binary files /dev/null and b/resources/sound/en/sound062.wav differ diff --git a/resources/sound/en/sound063.wav b/resources/sound/en/sound063.wav new file mode 100644 index 0000000..ac10526 Binary files /dev/null and b/resources/sound/en/sound063.wav differ diff --git a/resources/sound/en/sound064.wav b/resources/sound/en/sound064.wav new file mode 100644 index 0000000..d7b02d1 Binary files /dev/null and b/resources/sound/en/sound064.wav differ diff --git a/resources/sound/en/sound065.wav b/resources/sound/en/sound065.wav new file mode 100644 index 0000000..c8b1a7e Binary files /dev/null and b/resources/sound/en/sound065.wav differ diff --git a/resources/sound/en/sound066.wav b/resources/sound/en/sound066.wav new file mode 100644 index 0000000..08d1b8e Binary files /dev/null and b/resources/sound/en/sound066.wav differ diff --git a/resources/sound/en/sound067.wav b/resources/sound/en/sound067.wav new file mode 100644 index 0000000..a3911d7 Binary files /dev/null and b/resources/sound/en/sound067.wav differ diff --git a/resources/sound/en/sound068.wav b/resources/sound/en/sound068.wav new file mode 100644 index 0000000..e069e16 Binary files /dev/null and b/resources/sound/en/sound068.wav differ diff --git a/resources/sound/en/sound069.wav b/resources/sound/en/sound069.wav new file mode 100644 index 0000000..b902a16 Binary files /dev/null and b/resources/sound/en/sound069.wav differ diff --git a/resources/sound/en/sound070.wav b/resources/sound/en/sound070.wav new file mode 100644 index 0000000..8a843eb Binary files /dev/null and b/resources/sound/en/sound070.wav differ diff --git a/resources/sound/en/sound071.wav b/resources/sound/en/sound071.wav new file mode 100644 index 0000000..dbd4f0a Binary files /dev/null and b/resources/sound/en/sound071.wav differ diff --git a/resources/sound/en/sound072.wav b/resources/sound/en/sound072.wav new file mode 100644 index 0000000..1b591ef Binary files /dev/null and b/resources/sound/en/sound072.wav differ diff --git a/resources/sound/en/sound073.wav b/resources/sound/en/sound073.wav new file mode 100644 index 0000000..2e7c713 Binary files /dev/null and b/resources/sound/en/sound073.wav differ diff --git a/resources/sound/en/sound074.wav b/resources/sound/en/sound074.wav new file mode 100644 index 0000000..cc949d8 Binary files /dev/null and b/resources/sound/en/sound074.wav differ diff --git a/resources/sound/en/sound075.wav b/resources/sound/en/sound075.wav new file mode 100644 index 0000000..2536439 Binary files /dev/null and b/resources/sound/en/sound075.wav differ diff --git a/resources/sound/en/sound076.wav b/resources/sound/en/sound076.wav new file mode 100644 index 0000000..5471992 Binary files /dev/null and b/resources/sound/en/sound076.wav differ diff --git a/resources/sound/en/sound077.wav b/resources/sound/en/sound077.wav new file mode 100644 index 0000000..639249c Binary files /dev/null and b/resources/sound/en/sound077.wav differ diff --git a/resources/sound/en/sound078.wav b/resources/sound/en/sound078.wav new file mode 100644 index 0000000..b99f5d6 Binary files /dev/null and b/resources/sound/en/sound078.wav differ diff --git a/resources/sound/en/sound079.wav b/resources/sound/en/sound079.wav new file mode 100644 index 0000000..d43578a Binary files /dev/null and b/resources/sound/en/sound079.wav differ diff --git a/resources/sound/en/sound080.wav b/resources/sound/en/sound080.wav new file mode 100644 index 0000000..9230f43 Binary files /dev/null and b/resources/sound/en/sound080.wav differ diff --git a/resources/sound/en/sound081.wav b/resources/sound/en/sound081.wav new file mode 100644 index 0000000..f7fa9cf Binary files /dev/null and b/resources/sound/en/sound081.wav differ diff --git a/resources/sound/en/sound082.wav b/resources/sound/en/sound082.wav new file mode 100644 index 0000000..7526da4 Binary files /dev/null and b/resources/sound/en/sound082.wav differ diff --git a/resources/sound/en/sound083.wav b/resources/sound/en/sound083.wav new file mode 100644 index 0000000..dab5351 Binary files /dev/null and b/resources/sound/en/sound083.wav differ diff --git a/resources/sound/en/sound084.wav b/resources/sound/en/sound084.wav new file mode 100644 index 0000000..8bb6c2b Binary files /dev/null and b/resources/sound/en/sound084.wav differ diff --git a/resources/sound/en_US/sound002.wav b/resources/sound/en_US/sound002.wav new file mode 100644 index 0000000..979ddde Binary files /dev/null and b/resources/sound/en_US/sound002.wav differ diff --git a/resources/sound/en_US/sound003.wav b/resources/sound/en_US/sound003.wav new file mode 100644 index 0000000..4715187 Binary files /dev/null and b/resources/sound/en_US/sound003.wav differ diff --git a/resources/sound/en_US/sound004.wav b/resources/sound/en_US/sound004.wav new file mode 100644 index 0000000..a6678fd Binary files /dev/null and b/resources/sound/en_US/sound004.wav differ diff --git a/resources/sound/en_US/sound005.wav b/resources/sound/en_US/sound005.wav new file mode 100644 index 0000000..46bbf05 Binary files /dev/null and b/resources/sound/en_US/sound005.wav differ diff --git a/resources/sound/en_US/sound006.wav b/resources/sound/en_US/sound006.wav new file mode 100644 index 0000000..bc28c71 Binary files /dev/null and b/resources/sound/en_US/sound006.wav differ diff --git a/resources/sound/en_US/sound007.wav b/resources/sound/en_US/sound007.wav new file mode 100644 index 0000000..218dcab Binary files /dev/null and b/resources/sound/en_US/sound007.wav differ diff --git a/resources/sound/en_US/sound008.wav b/resources/sound/en_US/sound008.wav new file mode 100644 index 0000000..da2d55c Binary files /dev/null and b/resources/sound/en_US/sound008.wav differ diff --git a/resources/sound/en_US/sound009.wav b/resources/sound/en_US/sound009.wav new file mode 100644 index 0000000..11b74c4 Binary files /dev/null and b/resources/sound/en_US/sound009.wav differ diff --git a/resources/sound/en_US/sound010.wav b/resources/sound/en_US/sound010.wav new file mode 100644 index 0000000..84afb15 Binary files /dev/null and b/resources/sound/en_US/sound010.wav differ diff --git a/resources/sound/en_US/sound014.wav b/resources/sound/en_US/sound014.wav new file mode 100644 index 0000000..54bd89d Binary files /dev/null and b/resources/sound/en_US/sound014.wav differ diff --git a/resources/sound/en_US/sound017.wav b/resources/sound/en_US/sound017.wav new file mode 100644 index 0000000..53f78c9 Binary files /dev/null and b/resources/sound/en_US/sound017.wav differ diff --git a/resources/sound/en_US/sound018.wav b/resources/sound/en_US/sound018.wav new file mode 100644 index 0000000..a62165a Binary files /dev/null and b/resources/sound/en_US/sound018.wav differ diff --git a/resources/sound/en_US/sound019.wav b/resources/sound/en_US/sound019.wav new file mode 100644 index 0000000..ea2b374 Binary files /dev/null and b/resources/sound/en_US/sound019.wav differ diff --git a/resources/sound/en_US/sound027.wav b/resources/sound/en_US/sound027.wav new file mode 100644 index 0000000..5c2efaa Binary files /dev/null and b/resources/sound/en_US/sound027.wav differ diff --git a/resources/sound/en_US/sound033.wav b/resources/sound/en_US/sound033.wav new file mode 100644 index 0000000..edc69f5 Binary files /dev/null and b/resources/sound/en_US/sound033.wav differ diff --git a/resources/sound/en_US/sound037.wav b/resources/sound/en_US/sound037.wav new file mode 100644 index 0000000..0f190bc Binary files /dev/null and b/resources/sound/en_US/sound037.wav differ diff --git a/resources/sound/en_US/sound056.wav b/resources/sound/en_US/sound056.wav new file mode 100644 index 0000000..d332d31 Binary files /dev/null and b/resources/sound/en_US/sound056.wav differ diff --git a/resources/sound/en_US/sound057.wav b/resources/sound/en_US/sound057.wav new file mode 100644 index 0000000..433e2a7 Binary files /dev/null and b/resources/sound/en_US/sound057.wav differ diff --git a/resources/sound/en_US/sound058.wav b/resources/sound/en_US/sound058.wav new file mode 100644 index 0000000..db87560 Binary files /dev/null and b/resources/sound/en_US/sound058.wav differ diff --git a/resources/sound/en_US/sound059.wav b/resources/sound/en_US/sound059.wav new file mode 100644 index 0000000..b9f84f9 Binary files /dev/null and b/resources/sound/en_US/sound059.wav differ diff --git a/resources/sound/en_US/sound060.wav b/resources/sound/en_US/sound060.wav new file mode 100644 index 0000000..43da16a Binary files /dev/null and b/resources/sound/en_US/sound060.wav differ diff --git a/resources/sound/en_US/sound061.wav b/resources/sound/en_US/sound061.wav new file mode 100644 index 0000000..acfd9b8 Binary files /dev/null and b/resources/sound/en_US/sound061.wav differ diff --git a/resources/sound/en_US/sound062.wav b/resources/sound/en_US/sound062.wav new file mode 100644 index 0000000..454c3ac Binary files /dev/null and b/resources/sound/en_US/sound062.wav differ diff --git a/resources/sound/en_US/sound063.wav b/resources/sound/en_US/sound063.wav new file mode 100644 index 0000000..10fe748 Binary files /dev/null and b/resources/sound/en_US/sound063.wav differ diff --git a/resources/sound/en_US/sound064.wav b/resources/sound/en_US/sound064.wav new file mode 100644 index 0000000..2886ba3 Binary files /dev/null and b/resources/sound/en_US/sound064.wav differ diff --git a/resources/sound/en_US/sound065.wav b/resources/sound/en_US/sound065.wav new file mode 100644 index 0000000..88dc419 Binary files /dev/null and b/resources/sound/en_US/sound065.wav differ diff --git a/resources/sound/en_US/sound066.wav b/resources/sound/en_US/sound066.wav new file mode 100644 index 0000000..c59d2d3 Binary files /dev/null and b/resources/sound/en_US/sound066.wav differ diff --git a/resources/sound/en_US/sound067.wav b/resources/sound/en_US/sound067.wav new file mode 100644 index 0000000..831fbde Binary files /dev/null and b/resources/sound/en_US/sound067.wav differ diff --git a/resources/sound/en_US/sound068.wav b/resources/sound/en_US/sound068.wav new file mode 100644 index 0000000..b12f007 Binary files /dev/null and b/resources/sound/en_US/sound068.wav differ diff --git a/resources/sound/en_US/sound069.wav b/resources/sound/en_US/sound069.wav new file mode 100644 index 0000000..86751aa Binary files /dev/null and b/resources/sound/en_US/sound069.wav differ diff --git a/resources/sound/en_US/sound070.wav b/resources/sound/en_US/sound070.wav new file mode 100644 index 0000000..0c3f487 Binary files /dev/null and b/resources/sound/en_US/sound070.wav differ diff --git a/resources/sound/en_US/sound071.wav b/resources/sound/en_US/sound071.wav new file mode 100644 index 0000000..f6d6394 Binary files /dev/null and b/resources/sound/en_US/sound071.wav differ diff --git a/resources/sound/en_US/sound072.wav b/resources/sound/en_US/sound072.wav new file mode 100644 index 0000000..5e5372b Binary files /dev/null and b/resources/sound/en_US/sound072.wav differ diff --git a/resources/sound/en_US/sound073.wav b/resources/sound/en_US/sound073.wav new file mode 100644 index 0000000..4bc7834 Binary files /dev/null and b/resources/sound/en_US/sound073.wav differ diff --git a/resources/sound/fr/sound002.wav b/resources/sound/fr/sound002.wav new file mode 100644 index 0000000..97ee7f3 Binary files /dev/null and b/resources/sound/fr/sound002.wav differ diff --git a/resources/sound/fr/sound003.wav b/resources/sound/fr/sound003.wav new file mode 100644 index 0000000..e2f8334 Binary files /dev/null and b/resources/sound/fr/sound003.wav differ diff --git a/resources/sound/fr/sound004.wav b/resources/sound/fr/sound004.wav new file mode 100644 index 0000000..f45dd08 Binary files /dev/null and b/resources/sound/fr/sound004.wav differ diff --git a/resources/sound/fr/sound005.wav b/resources/sound/fr/sound005.wav new file mode 100644 index 0000000..7c15283 Binary files /dev/null and b/resources/sound/fr/sound005.wav differ diff --git a/resources/sound/fr/sound006.wav b/resources/sound/fr/sound006.wav new file mode 100644 index 0000000..ccb0c8c Binary files /dev/null and b/resources/sound/fr/sound006.wav differ diff --git a/resources/sound/fr/sound007.wav b/resources/sound/fr/sound007.wav new file mode 100644 index 0000000..c6f383c Binary files /dev/null and b/resources/sound/fr/sound007.wav differ diff --git a/resources/sound/fr/sound008.wav b/resources/sound/fr/sound008.wav new file mode 100644 index 0000000..5839ea0 Binary files /dev/null and b/resources/sound/fr/sound008.wav differ diff --git a/resources/sound/fr/sound009.wav b/resources/sound/fr/sound009.wav new file mode 100644 index 0000000..f7cbc8f Binary files /dev/null and b/resources/sound/fr/sound009.wav differ diff --git a/resources/sound/fr/sound010.wav b/resources/sound/fr/sound010.wav new file mode 100644 index 0000000..7edb4e6 Binary files /dev/null and b/resources/sound/fr/sound010.wav differ diff --git a/resources/sound/fr/sound014.wav b/resources/sound/fr/sound014.wav new file mode 100644 index 0000000..244205f Binary files /dev/null and b/resources/sound/fr/sound014.wav differ diff --git a/resources/sound/fr/sound017.wav b/resources/sound/fr/sound017.wav new file mode 100644 index 0000000..68b65e5 Binary files /dev/null and b/resources/sound/fr/sound017.wav differ diff --git a/resources/sound/fr/sound018.wav b/resources/sound/fr/sound018.wav new file mode 100644 index 0000000..3fe6ec6 Binary files /dev/null and b/resources/sound/fr/sound018.wav differ diff --git a/resources/sound/fr/sound019.wav b/resources/sound/fr/sound019.wav new file mode 100644 index 0000000..15ac76c Binary files /dev/null and b/resources/sound/fr/sound019.wav differ diff --git a/resources/sound/fr/sound027.wav b/resources/sound/fr/sound027.wav new file mode 100644 index 0000000..3cbe230 Binary files /dev/null and b/resources/sound/fr/sound027.wav differ diff --git a/resources/sound/fr/sound033.wav b/resources/sound/fr/sound033.wav new file mode 100644 index 0000000..c4b3427 Binary files /dev/null and b/resources/sound/fr/sound033.wav differ diff --git a/resources/sound/fr/sound037.wav b/resources/sound/fr/sound037.wav new file mode 100644 index 0000000..3d8fc1a Binary files /dev/null and b/resources/sound/fr/sound037.wav differ diff --git a/resources/sound/fr/sound056.wav b/resources/sound/fr/sound056.wav new file mode 100644 index 0000000..d4bb2c8 Binary files /dev/null and b/resources/sound/fr/sound056.wav differ diff --git a/resources/sound/fr/sound057.wav b/resources/sound/fr/sound057.wav new file mode 100644 index 0000000..cd5b232 Binary files /dev/null and b/resources/sound/fr/sound057.wav differ diff --git a/resources/sound/fr/sound058.wav b/resources/sound/fr/sound058.wav new file mode 100644 index 0000000..8ffff03 Binary files /dev/null and b/resources/sound/fr/sound058.wav differ diff --git a/resources/sound/fr/sound059.wav b/resources/sound/fr/sound059.wav new file mode 100644 index 0000000..7d9753c Binary files /dev/null and b/resources/sound/fr/sound059.wav differ diff --git a/resources/sound/fr/sound060.wav b/resources/sound/fr/sound060.wav new file mode 100644 index 0000000..f03e957 Binary files /dev/null and b/resources/sound/fr/sound060.wav differ diff --git a/resources/sound/fr/sound061.wav b/resources/sound/fr/sound061.wav new file mode 100644 index 0000000..c8d8584 Binary files /dev/null and b/resources/sound/fr/sound061.wav differ diff --git a/resources/sound/fr/sound062.wav b/resources/sound/fr/sound062.wav new file mode 100644 index 0000000..64e4ec1 Binary files /dev/null and b/resources/sound/fr/sound062.wav differ diff --git a/resources/sound/fr/sound063.wav b/resources/sound/fr/sound063.wav new file mode 100644 index 0000000..dd02a5d Binary files /dev/null and b/resources/sound/fr/sound063.wav differ diff --git a/resources/sound/fr/sound064.wav b/resources/sound/fr/sound064.wav new file mode 100644 index 0000000..364b7c0 Binary files /dev/null and b/resources/sound/fr/sound064.wav differ diff --git a/resources/sound/fr/sound065.wav b/resources/sound/fr/sound065.wav new file mode 100644 index 0000000..1d314d2 Binary files /dev/null and b/resources/sound/fr/sound065.wav differ diff --git a/resources/sound/fr/sound066.wav b/resources/sound/fr/sound066.wav new file mode 100644 index 0000000..08d4bf7 Binary files /dev/null and b/resources/sound/fr/sound066.wav differ diff --git a/resources/sound/fr/sound067.wav b/resources/sound/fr/sound067.wav new file mode 100644 index 0000000..1e0450b Binary files /dev/null and b/resources/sound/fr/sound067.wav differ diff --git a/resources/sound/fr/sound068.wav b/resources/sound/fr/sound068.wav new file mode 100644 index 0000000..d298f02 Binary files /dev/null and b/resources/sound/fr/sound068.wav differ diff --git a/resources/sound/fr/sound069.wav b/resources/sound/fr/sound069.wav new file mode 100644 index 0000000..7e72a90 Binary files /dev/null and b/resources/sound/fr/sound069.wav differ diff --git a/resources/sound/fr/sound070.wav b/resources/sound/fr/sound070.wav new file mode 100644 index 0000000..d3fb00a Binary files /dev/null and b/resources/sound/fr/sound070.wav differ diff --git a/resources/sound/fr/sound071.wav b/resources/sound/fr/sound071.wav new file mode 100644 index 0000000..f5d3b87 Binary files /dev/null and b/resources/sound/fr/sound071.wav differ diff --git a/resources/sound/fr/sound072.wav b/resources/sound/fr/sound072.wav new file mode 100644 index 0000000..20a576b Binary files /dev/null and b/resources/sound/fr/sound072.wav differ diff --git a/resources/sound/fr/sound073.wav b/resources/sound/fr/sound073.wav new file mode 100644 index 0000000..da6f207 Binary files /dev/null and b/resources/sound/fr/sound073.wav differ diff --git a/resources/sound/he/sound002.wav b/resources/sound/he/sound002.wav new file mode 100644 index 0000000..ca71d55 Binary files /dev/null and b/resources/sound/he/sound002.wav differ diff --git a/resources/sound/he/sound003.wav b/resources/sound/he/sound003.wav new file mode 100644 index 0000000..57de5a4 Binary files /dev/null and b/resources/sound/he/sound003.wav differ diff --git a/resources/sound/he/sound004.wav b/resources/sound/he/sound004.wav new file mode 100644 index 0000000..4a4ba64 Binary files /dev/null and b/resources/sound/he/sound004.wav differ diff --git a/resources/sound/he/sound005.wav b/resources/sound/he/sound005.wav new file mode 100644 index 0000000..b6543e0 Binary files /dev/null and b/resources/sound/he/sound005.wav differ diff --git a/resources/sound/he/sound006.wav b/resources/sound/he/sound006.wav new file mode 100644 index 0000000..31202ea Binary files /dev/null and b/resources/sound/he/sound006.wav differ diff --git a/resources/sound/he/sound007.wav b/resources/sound/he/sound007.wav new file mode 100644 index 0000000..f4d3a38 Binary files /dev/null and b/resources/sound/he/sound007.wav differ diff --git a/resources/sound/he/sound008.wav b/resources/sound/he/sound008.wav new file mode 100644 index 0000000..357fcb2 Binary files /dev/null and b/resources/sound/he/sound008.wav differ diff --git a/resources/sound/he/sound009.wav b/resources/sound/he/sound009.wav new file mode 100644 index 0000000..cefb054 Binary files /dev/null and b/resources/sound/he/sound009.wav differ diff --git a/resources/sound/he/sound010.wav b/resources/sound/he/sound010.wav new file mode 100644 index 0000000..d3e8822 Binary files /dev/null and b/resources/sound/he/sound010.wav differ diff --git a/resources/sound/he/sound014.wav b/resources/sound/he/sound014.wav new file mode 100644 index 0000000..d5a152b Binary files /dev/null and b/resources/sound/he/sound014.wav differ diff --git a/resources/sound/he/sound017.wav b/resources/sound/he/sound017.wav new file mode 100644 index 0000000..493f56e Binary files /dev/null and b/resources/sound/he/sound017.wav differ diff --git a/resources/sound/he/sound018.wav b/resources/sound/he/sound018.wav new file mode 100644 index 0000000..025bba0 Binary files /dev/null and b/resources/sound/he/sound018.wav differ diff --git a/resources/sound/he/sound019.wav b/resources/sound/he/sound019.wav new file mode 100644 index 0000000..5f09c76 Binary files /dev/null and b/resources/sound/he/sound019.wav differ diff --git a/resources/sound/he/sound027.wav b/resources/sound/he/sound027.wav new file mode 100644 index 0000000..6454aa5 Binary files /dev/null and b/resources/sound/he/sound027.wav differ diff --git a/resources/sound/he/sound033.wav b/resources/sound/he/sound033.wav new file mode 100644 index 0000000..b2be5eb Binary files /dev/null and b/resources/sound/he/sound033.wav differ diff --git a/resources/sound/he/sound037.wav b/resources/sound/he/sound037.wav new file mode 100644 index 0000000..38f5676 Binary files /dev/null and b/resources/sound/he/sound037.wav differ diff --git a/resources/sound/he/sound056.wav b/resources/sound/he/sound056.wav new file mode 100644 index 0000000..b290ff8 Binary files /dev/null and b/resources/sound/he/sound056.wav differ diff --git a/resources/sound/he/sound057.wav b/resources/sound/he/sound057.wav new file mode 100644 index 0000000..d8c2397 Binary files /dev/null and b/resources/sound/he/sound057.wav differ diff --git a/resources/sound/he/sound058.wav b/resources/sound/he/sound058.wav new file mode 100644 index 0000000..f980342 Binary files /dev/null and b/resources/sound/he/sound058.wav differ diff --git a/resources/sound/he/sound059.wav b/resources/sound/he/sound059.wav new file mode 100644 index 0000000..5b99e65 Binary files /dev/null and b/resources/sound/he/sound059.wav differ diff --git a/resources/sound/he/sound060.wav b/resources/sound/he/sound060.wav new file mode 100644 index 0000000..5e2a023 Binary files /dev/null and b/resources/sound/he/sound060.wav differ diff --git a/resources/sound/he/sound061.wav b/resources/sound/he/sound061.wav new file mode 100644 index 0000000..9f33567 Binary files /dev/null and b/resources/sound/he/sound061.wav differ diff --git a/resources/sound/he/sound062.wav b/resources/sound/he/sound062.wav new file mode 100644 index 0000000..95a617f Binary files /dev/null and b/resources/sound/he/sound062.wav differ diff --git a/resources/sound/he/sound063.wav b/resources/sound/he/sound063.wav new file mode 100644 index 0000000..b74eef5 Binary files /dev/null and b/resources/sound/he/sound063.wav differ diff --git a/resources/sound/he/sound064.wav b/resources/sound/he/sound064.wav new file mode 100644 index 0000000..17cd655 Binary files /dev/null and b/resources/sound/he/sound064.wav differ diff --git a/resources/sound/he/sound065.wav b/resources/sound/he/sound065.wav new file mode 100644 index 0000000..3172e73 Binary files /dev/null and b/resources/sound/he/sound065.wav differ diff --git a/resources/sound/he/sound066.wav b/resources/sound/he/sound066.wav new file mode 100644 index 0000000..53cc32f Binary files /dev/null and b/resources/sound/he/sound066.wav differ diff --git a/resources/sound/he/sound067.wav b/resources/sound/he/sound067.wav new file mode 100644 index 0000000..9048cc2 Binary files /dev/null and b/resources/sound/he/sound067.wav differ diff --git a/resources/sound/he/sound068.wav b/resources/sound/he/sound068.wav new file mode 100644 index 0000000..07837aa Binary files /dev/null and b/resources/sound/he/sound068.wav differ diff --git a/resources/sound/he/sound069.wav b/resources/sound/he/sound069.wav new file mode 100644 index 0000000..baeaa7e Binary files /dev/null and b/resources/sound/he/sound069.wav differ diff --git a/resources/sound/he/sound070.wav b/resources/sound/he/sound070.wav new file mode 100644 index 0000000..90a1d87 Binary files /dev/null and b/resources/sound/he/sound070.wav differ diff --git a/resources/sound/he/sound071.wav b/resources/sound/he/sound071.wav new file mode 100644 index 0000000..364fd00 Binary files /dev/null and b/resources/sound/he/sound071.wav differ diff --git a/resources/sound/he/sound072.wav b/resources/sound/he/sound072.wav new file mode 100644 index 0000000..cc3f456 Binary files /dev/null and b/resources/sound/he/sound072.wav differ diff --git a/resources/sound/he/sound073.wav b/resources/sound/he/sound073.wav new file mode 100644 index 0000000..aacb0cf Binary files /dev/null and b/resources/sound/he/sound073.wav differ diff --git a/resources/sound/it/sound002.wav b/resources/sound/it/sound002.wav new file mode 100644 index 0000000..c19b707 Binary files /dev/null and b/resources/sound/it/sound002.wav differ diff --git a/resources/sound/it/sound003.wav b/resources/sound/it/sound003.wav new file mode 100644 index 0000000..d307723 Binary files /dev/null and b/resources/sound/it/sound003.wav differ diff --git a/resources/sound/it/sound004.wav b/resources/sound/it/sound004.wav new file mode 100644 index 0000000..c0672c7 Binary files /dev/null and b/resources/sound/it/sound004.wav differ diff --git a/resources/sound/it/sound005.wav b/resources/sound/it/sound005.wav new file mode 100644 index 0000000..25ac116 Binary files /dev/null and b/resources/sound/it/sound005.wav differ diff --git a/resources/sound/it/sound006.wav b/resources/sound/it/sound006.wav new file mode 100644 index 0000000..a34045d Binary files /dev/null and b/resources/sound/it/sound006.wav differ diff --git a/resources/sound/it/sound007.wav b/resources/sound/it/sound007.wav new file mode 100644 index 0000000..6ac6dd5 Binary files /dev/null and b/resources/sound/it/sound007.wav differ diff --git a/resources/sound/it/sound008.wav b/resources/sound/it/sound008.wav new file mode 100644 index 0000000..ffc5efd Binary files /dev/null and b/resources/sound/it/sound008.wav differ diff --git a/resources/sound/it/sound009.wav b/resources/sound/it/sound009.wav new file mode 100644 index 0000000..5d6478c Binary files /dev/null and b/resources/sound/it/sound009.wav differ diff --git a/resources/sound/it/sound010.wav b/resources/sound/it/sound010.wav new file mode 100644 index 0000000..b6860bb Binary files /dev/null and b/resources/sound/it/sound010.wav differ diff --git a/resources/sound/it/sound014.wav b/resources/sound/it/sound014.wav new file mode 100644 index 0000000..a8556b1 Binary files /dev/null and b/resources/sound/it/sound014.wav differ diff --git a/resources/sound/it/sound017.wav b/resources/sound/it/sound017.wav new file mode 100644 index 0000000..4cffd22 Binary files /dev/null and b/resources/sound/it/sound017.wav differ diff --git a/resources/sound/it/sound018.wav b/resources/sound/it/sound018.wav new file mode 100644 index 0000000..93c117e Binary files /dev/null and b/resources/sound/it/sound018.wav differ diff --git a/resources/sound/it/sound019.wav b/resources/sound/it/sound019.wav new file mode 100644 index 0000000..e403b8c Binary files /dev/null and b/resources/sound/it/sound019.wav differ diff --git a/resources/sound/it/sound027.wav b/resources/sound/it/sound027.wav new file mode 100644 index 0000000..b006541 Binary files /dev/null and b/resources/sound/it/sound027.wav differ diff --git a/resources/sound/it/sound033.wav b/resources/sound/it/sound033.wav new file mode 100644 index 0000000..845c263 Binary files /dev/null and b/resources/sound/it/sound033.wav differ diff --git a/resources/sound/it/sound037.wav b/resources/sound/it/sound037.wav new file mode 100644 index 0000000..089204e Binary files /dev/null and b/resources/sound/it/sound037.wav differ diff --git a/resources/sound/it/sound056.wav b/resources/sound/it/sound056.wav new file mode 100644 index 0000000..9ae8904 Binary files /dev/null and b/resources/sound/it/sound056.wav differ diff --git a/resources/sound/it/sound057.wav b/resources/sound/it/sound057.wav new file mode 100644 index 0000000..5e6b602 Binary files /dev/null and b/resources/sound/it/sound057.wav differ diff --git a/resources/sound/it/sound058.wav b/resources/sound/it/sound058.wav new file mode 100644 index 0000000..30d1a0a Binary files /dev/null and b/resources/sound/it/sound058.wav differ diff --git a/resources/sound/it/sound059.wav b/resources/sound/it/sound059.wav new file mode 100644 index 0000000..9df9b59 Binary files /dev/null and b/resources/sound/it/sound059.wav differ diff --git a/resources/sound/it/sound060.wav b/resources/sound/it/sound060.wav new file mode 100644 index 0000000..f09c5c5 Binary files /dev/null and b/resources/sound/it/sound060.wav differ diff --git a/resources/sound/it/sound061.wav b/resources/sound/it/sound061.wav new file mode 100644 index 0000000..8f57fa4 Binary files /dev/null and b/resources/sound/it/sound061.wav differ diff --git a/resources/sound/it/sound062.wav b/resources/sound/it/sound062.wav new file mode 100644 index 0000000..6810088 Binary files /dev/null and b/resources/sound/it/sound062.wav differ diff --git a/resources/sound/it/sound063.wav b/resources/sound/it/sound063.wav new file mode 100644 index 0000000..2d4efdf Binary files /dev/null and b/resources/sound/it/sound063.wav differ diff --git a/resources/sound/it/sound064.wav b/resources/sound/it/sound064.wav new file mode 100644 index 0000000..fcee0f2 Binary files /dev/null and b/resources/sound/it/sound064.wav differ diff --git a/resources/sound/it/sound065.wav b/resources/sound/it/sound065.wav new file mode 100644 index 0000000..f1cdbba Binary files /dev/null and b/resources/sound/it/sound065.wav differ diff --git a/resources/sound/it/sound066.wav b/resources/sound/it/sound066.wav new file mode 100644 index 0000000..825ad46 Binary files /dev/null and b/resources/sound/it/sound066.wav differ diff --git a/resources/sound/it/sound067.wav b/resources/sound/it/sound067.wav new file mode 100644 index 0000000..9f4989b Binary files /dev/null and b/resources/sound/it/sound067.wav differ diff --git a/resources/sound/it/sound068.wav b/resources/sound/it/sound068.wav new file mode 100644 index 0000000..f479d55 Binary files /dev/null and b/resources/sound/it/sound068.wav differ diff --git a/resources/sound/it/sound069.wav b/resources/sound/it/sound069.wav new file mode 100644 index 0000000..e58fe6b Binary files /dev/null and b/resources/sound/it/sound069.wav differ diff --git a/resources/sound/it/sound070.wav b/resources/sound/it/sound070.wav new file mode 100644 index 0000000..c0c7ce7 Binary files /dev/null and b/resources/sound/it/sound070.wav differ diff --git a/resources/sound/it/sound071.wav b/resources/sound/it/sound071.wav new file mode 100644 index 0000000..fa780d0 Binary files /dev/null and b/resources/sound/it/sound071.wav differ diff --git a/resources/sound/it/sound072.wav b/resources/sound/it/sound072.wav new file mode 100644 index 0000000..bfc4aea Binary files /dev/null and b/resources/sound/it/sound072.wav differ diff --git a/resources/sound/it/sound073.wav b/resources/sound/it/sound073.wav new file mode 100644 index 0000000..839bf05 Binary files /dev/null and b/resources/sound/it/sound073.wav differ diff --git a/resources/win32/planetblupi.rc.in b/resources/win32/planetblupi.rc.in new file mode 100644 index 0000000..f9f4cf9 --- /dev/null +++ b/resources/win32/planetblupi.rc.in @@ -0,0 +1,25 @@ +id ICON "blupi.ico" + +1 VERSIONINFO +FILEVERSION @PB_VERSION_MAJOR@,@PB_VERSION_MINOR@,0,@PB_VERSION_PATCH@ +PRODUCTVERSION @PB_VERSION_MAJOR@,@PB_VERSION_MINOR@,0,@PB_VERSION_PATCH@ +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "CompanyName", "Epsitec SA" + VALUE "FileDescription", "@PB_DESCRIPTION@" + VALUE "FileVersion", "@PB_VERSION_MAJOR@.@PB_VERSION_MINOR@.@PB_VERSION_PATCH@@PB_VERSION_EXTRA@" + VALUE "InternalName", "@PB_PACKAGE_NAME@" + VALUE "LegalCopyright", "Epsitec SA, Daniel Roux and Mathieu Schroeter" + VALUE "OriginalFilename", "@PB_PACKAGE_NAME@.exe" + VALUE "ProductName", "@PB_PRODUCT_NAME@" + VALUE "ProductVersion", "@PB_VERSION_MAJOR@.@PB_VERSION_MINOR@.@PB_VERSION_PATCH@@PB_VERSION_EXTRA@" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END diff --git a/src/.clang-format b/src/.clang-format new file mode 100644 index 0000000..5c925b2 --- /dev/null +++ b/src/.clang-format @@ -0,0 +1,97 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: AlwaysBreak +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true +AlignEscapedNewlinesLeft: true +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: TopLevelDefinitions +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: true +#BreakAfterJavaFieldAnnotations: false +#BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 2 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +#FixNamespaceComments: true +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeCategories: + - Regex: '(stdafx|STDAFX|StdAfx)\.[hH]' + Priority: -1 + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +#IncludeIsMainRegex: '$' +IndentCaseLabels: false +IndentWidth: 2 +IndentWrappedFunctionNames: false +#JavaScriptQuotes: Leave +#JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: "^BEGIN_MESSAGE_MAP$" +MacroBlockEnd: "^END_MESSAGE_MAP$" +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Middle +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: Always +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... diff --git a/src/action.cxx b/src/action.cxx new file mode 100644 index 0000000..764b778 --- /dev/null +++ b/src/action.cxx @@ -0,0 +1,2931 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include +#include + +#include "action.h" +#include "def.h" +#include "misc.h" + +#define MAXICON (1 + 50) +#define MAXMOVE (2 + 30 * 3) +#define MAXSOUND (1 + 50) + +struct DescAction { + Sint16 action; + Sint16 channel; + Sint16 icons[8][MAXICON]; // nb, icones, + Sint16 moves[8][MAXMOVE]; // nb, nb, x,y, + Sint16 sounds[MAXSOUND]; // nb, sons, +}; + +// clang-format off +static const DescAction action_table[] = +{ + { + ACTION_STOP, + CHBLUPI, + { + {1, 48}, // e + {1, 49}, // se + {1, 50}, // s + {1, 51}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {1, 55}, // ne + }, + { + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_STOPTIRED, + CHBLUPI, + { + {1, 69}, // e + {1, 72}, // se + {1, 75}, // s + {1, 78}, // so + {1, 81}, // o + {1, 84}, // no + {1, 87}, // n + {1, 90}, // ne + }, + { + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_STOPb, + CHBLUPI, + { + {1, 48}, // e + {1, 49}, // se + {1, 50}, // s + {1, 51}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {1, 55}, // ne + }, + { + { 10, 10, 0, 0, +1, 0, 0, +1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + { 10, 10, 0, 0, +1, 0, 0, +1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + { 10, 10, 0, 0, +1, 0, 0, +1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + { 10, 10, 0, 0, +1, 0, 0, +1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + { 10, 10, 0, 0, +1, 0, 0, +1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + { 10, 10, 0, 0, +1, 0, 0, +1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + { 10, 10, 0, 0, +1, 0, 0, +1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + { 10, 10, 0, 0, +1, 0, 0, +1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + }, + {0}, + }, + { + ACTION_STOPJEEP, + CHBLUPI, + { + {1, 48}, // e + {1, 49}, // se + {1, 50}, // s + {1, 51}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {1, 55}, // ne + }, + { + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_STOPARMOR, + CHBLUPI, + { + {1, 322}, // e + {1, 325}, // se + {1, 328}, // s + {1, 331}, // so + {1, 334}, // o + {1, 337}, // no + {1, 340}, // n + {1, 343}, // ne + }, + { + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_ENERGY, + CHBLUPI, + { + {1, 48}, // e + {1, 49}, // se + {1, 50}, // s + {1, 51}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {1, 55}, // ne + }, + { + {2, 2, 0, 0, -2, 0, 0, +2}, + {2, 2, 0, 0, -2, 0, 0, +2}, + {2, 2, 0, 0, -2, 0, 0, +2}, + {2, 2, 0, 0, -2, 0, 0, +2}, + {2, 2, 0, 0, -2, 0, 0, +2}, + {2, 2, 0, 0, -2, 0, 0, +2}, + {2, 2, 0, 0, -2, 0, 0, +2}, + {2, 2, 0, 0, -2, 0, 0, +2}, + }, + {0}, + }, + { + ACTION_WALK, + CHBLUPI, + { + {6, 0, 1, 2, 3, 4, 5}, // e + {6, 6, 7, 8, 9, 10, 11}, // se + {6, 12, 13, 14, 15, 16, 17}, // s + {6, 18, 19, 20, 21, 22, 23}, // so + {6, 24, 25, 26, 27, 28, 29}, // o + {6, 30, 31, 32, 33, 34, 35}, // no + {6, 36, 37, 38, 39, 40, 41}, // n + {6, 42, 43, 44, 45, 46, 47}, // ne + }, + { +#if 1 + {10, 1, +300, +150, 0}, // e + {15, 1, 0, +200, 0}, // se + {10, 1, -300, +150, 0}, // s + {15, 1, -400, 0, 0}, // so + {10, 1, -300, -150, 0}, // o + {15, 1, 0, -200, 0}, // no + {10, 1, +300, -150, 0}, // n + {15, 1, +400, 0, 0}, // ne +#else + {15, 1, +200, +100, 0}, // e + {20, 1, 0, +150, 0}, // se + {15, 1, -200, +100, 0}, // s + {20, 1, -300, 0, 0}, // so + {15, 1, -200, -100, 0}, // o + {20, 1, 0, -150, 0}, // no + {15, 1, +200, -100, 0}, // n + {20, 1, +300, 0, 0}, // ne +#endif + }, + {0}, + }, + { + ACTION_WALKTIRED, + CHBLUPI, + { + {8, 69, 69, 70, 70, 69, 69, 71, 71}, // e + {8, 72, 72, 73, 73, 72, 72, 74, 74}, // se + {8, 75, 75, 76, 76, 75, 75, 77, 77}, // s + {8, 78, 78, 79, 79, 78, 78, 80, 80}, // so + {8, 81, 81, 82, 82, 81, 81, 83, 83}, // o + {8, 84, 84, 85, 85, 84, 84, 86, 86}, // no + {8, 87, 87, 88, 88, 87, 87, 89, 89}, // n + {8, 90, 90, 91, 91, 90, 90, 92, 92}, // ne + }, + { + {20, 2, 0, 0, 0, +300, +150, 0}, // e + {30, 2, 0, 0, 0, 0, +200, 0}, // se + {20, 2, 0, 0, 0, -300, +150, 0}, // s + {30, 2, 0, 0, 0, -400, 0, 0}, // so + {20, 2, 0, 0, 0, -300, -150, 0}, // o + {30, 2, 0, 0, 0, 0, -200, 0}, // no + {20, 2, 0, 0, 0, +300, -150, 0}, // n + {30, 2, 0, 0, 0, +400, 0, 0}, // ne + }, + {0}, + }, + { + ACTION_MARCHEb, + CHBLUPI, + { + {1, 48}, // e + {1, 49}, // se + {1, 50}, // s + {1, 51}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {1, 55}, // ne + }, + { +#if 0 + { 20, 10, +150, +75, +1, +150, +75, +1, +150, +75, +1, + +150, +75, 0, +150, +75, 0, +150, +75, 0, +150, +75, 0, + +150, +75, -1, +150, +75, -1, +150, +75, -1 + }, + { 30, 10, 0, +100, +1, 0, +100, +1, 0, +100, +1, + 0, +100, 0, 0, +100, 0, 0, +100, 0, 0, +100, 0, + 0, +100, -1, 0, +100, -1, 0, +100, -1 + }, + { 20, 10, -150, +75, +1, -150, +75, +1, -150, +75, +1, + -150, +75, 0, -150, +75, 0, -150, +75, 0, -150, +75, 0, + -150, +75, -1, -150, +75, -1, -150, +75, -1 + }, + { 30, 10, -200, 0, +1, -200, 0, +1, -200, 0, +1, + -200, 0, 0, -200, 0, 0, -200, 0, 0, -200, 0, 0, + -200, 0, -1, -200, 0, -1, -200, 0, -1 + }, + { 20, 10, -150, -75, +1, -150, -75, +1, -150, -75, +1, + -150, -75, 0, -150, -75, 0, -150, -75, 0, -150, -75, 0, + -150, -75, -1, -150, -75, -1, -150, -75, -1 + }, + { 30, 10, 0, -100, +1, 0, -100, +1, 0, -100, +1, + 0, -100, 0, 0, -100, 0, 0, -100, 0, 0, -100, 0, + 0, -100, -1, 0, -100, -1, 0, -100, -1 + }, + { 20, 10, +150, -75, +1, +150, -75, +1, +150, -75, +1, + +150, -75, 0, +150, -75, 0, +150, -75, 0, +150, -75, 0, + +150, -75, -1, +150, -75, -1, +150, -75, -1 + }, + { 30, 10, +200, 0, +1, +200, 0, +1, +200, 0, +1, + +200, 0, 0, +200, 0, 0, +200, 0, 0, +200, 0, 0, + +200, 0, -1, +200, 0, -1, +200, 0, -1 + }, +#else + { 5, 5, +600, +300, +1, +600, +300, +1, +600, +300, 0, +600, +300, -1, +600, +300, -1}, + {10, 5, 0, +300, +1, 0, +300, +1, 0, +300, 0, 0, +300, -1, 0, +300, -1}, + { 5, 5, -600, +300, +1, -600, +300, +1, -600, +300, 0, -600, +300, -1, -600, +300, -1}, + {10, 5, -600, 0, +1, -600, 0, +1, -600, 0, 0, -600, 0, -1, -600, 0, -1}, + { 5, 5, -600, -300, +1, -600, -300, +1, -600, -300, 0, -600, -300, -1, -600, -300, -1}, + {10, 5, 0, -300, +1, 0, -300, +1, 0, -300, 0, 0, -300, -1, 0, -300, -1}, + { 5, 5, +600, -300, +1, +600, -300, +1, +600, -300, 0, +600, -300, -1, +600, -300, -1}, + {10, 5, +600, 0, +1, +600, 0, +1, +600, 0, 0, +600, 0, -1, +600, 0, -1}, +#endif + }, + { 20, -1, -1, SOUND_BOAT, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }, + }, + { + ACTION_WALKJEEP, + CHBLUPI, + { + {1, 48}, // e + {1, 49}, // se + {1, 50}, // s + {1, 51}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {1, 55}, // ne + }, + { + {5, 1, +600, +300, 0}, + {7, 1, 0, +429, 0}, + {5, 1, -600, +300, 0}, + {7, 1, -858, 0, 0}, + {5, 1, -600, -300, 0}, + {7, 1, 0, -429, 0}, + {5, 1, +600, -300, 0}, + {7, 1, +858, 0, 0}, + }, + { 20, -1, -1, SOUND_JEEP, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }, + }, + { + ACTION_WALKARMOR, + CHBLUPI, + { + {8, 322, 322, 323, 323, 322, 322, 324, 324}, // e + {8, 325, 325, 326, 326, 325, 325, 327, 327}, // se + {8, 328, 328, 329, 329, 328, 328, 330, 330}, // s + {8, 331, 331, 332, 332, 331, 331, 333, 333}, // so + {8, 334, 334, 335, 335, 334, 334, 336, 336}, // o + {8, 337, 337, 338, 338, 337, 337, 339, 339}, // no + {8, 340, 340, 341, 341, 340, 340, 342, 342}, // n + {8, 343, 343, 344, 344, 343, 343, 345, 345}, // ne + }, + { + {10, 2, 0, 0, 0, +600, +300, 0}, // e + {16, 2, 0, 0, 0, 0, +375, 0}, // se + {10, 2, 0, 0, 0, -600, +300, 0}, // s + {16, 2, 0, 0, 0, -750, 0, 0}, // so + {10, 2, 0, 0, 0, -600, -300, 0}, // o + {16, 2, 0, 0, 0, 0, -375, 0}, // no + {10, 2, 0, 0, 0, +600, -300, 0}, // n + {16, 2, 0, 0, 0, +750, 0, 0}, // ne + }, + {0}, + }, + { + ACTION_JUMPJEEP, + CHBLUPI, + { + { 15, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, + 136, 106, 106, 106, 106 + }, // e + {1, 6}, // se + { 15, 133, 133, 133, 133, 133, 137, 137, 137, 137, 137, + 137, 133, 133, 133, 133 + }, // s + {1, 18}, // so + { 15, 134, 134, 134, 134, 134, 138, 138, 138, 138, 138, + 138, 134, 134, 134, 134 + }, // o + {1, 30}, // no + { 15, 135, 135, 135, 135, 135, 139, 139, 139, 139, 139, + 139, 135, 135, 135, 135 + }, // n + {1, 42}, // ne + }, + { + { 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +300, +150, -5, +300, +150, -5, +300, +150, -5, + +300, +150, -5, +300, +150, -2, + +300, +150, +2, +300, +150, +5, +300, +150, +5, + +300, +150, +5, +300, +150, +5 + }, // e + {1, 1, 0, 0, 0}, // se + { 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -300, +150, -5, -300, +150, -5, -300, +150, -5, + -300, +150, -5, -300, +150, -2, + -300, +150, +2, -300, +150, +5, -300, +150, +5, + -300, +150, +5, -300, +150, +5 + }, // s + {1, 1, 0, 0, 0}, // so + { 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -300, -150, -5, -300, -150, -5, -300, -150, -5, + -300, -150, -5, -300, -150, -2, + -300, -150, +2, -300, -150, +5, -300, -150, +5, + -300, -150, +5, -300, -150, +5 + }, // o + {1, 1, 0, 0, 0}, // no + { 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +300, -150, -5, +300, -150, -5, +300, -150, -5, + +300, -150, -5, +300, -150, -2, + +300, -150, +2, +300, -150, +5, +300, -150, +5, + +300, -150, +5, +300, -150, +5 + }, // n + {1, 1, 0, 0, 0}, // ne + }, + { 15, SOUND_HOP, -1, -1, -1, + SOUND_JUMP, -1, -1, -1, -1, -1, -1, -1, -1, -1, + SOUND_COUPTOC + }, + }, + { + ACTION_JUMP2, + CHBLUPI, + { + { 15, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, + 136, 106, 106, 106, 106 + }, // e + {1, 6}, // se + { 15, 133, 133, 133, 133, 133, 137, 137, 137, 137, 137, + 137, 133, 133, 133, 133 + }, // s + {1, 18}, // so + { 15, 134, 134, 134, 134, 134, 138, 138, 138, 138, 138, + 138, 134, 134, 134, 134 + }, // o + {1, 30}, // no + { 15, 135, 135, 135, 135, 135, 139, 139, 139, 139, 139, + 139, 135, 135, 135, 135 + }, // n + {1, 42}, // ne + }, + { + { 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +600, +300, -5, +600, +300, -5, +600, +300, -5, + +600, +300, -5, +600, +300, -2, + +600, +300, +2, +600, +300, +5, +600, +300, +5, + +600, +300, +5, +600, +300, +5 + }, // e + {1, 1, 0, 0, 0}, // se + { 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -600, +300, -5, -600, +300, -5, -600, +300, -5, + -600, +300, -5, -600, +300, -2, + -600, +300, +2, -600, +300, +5, -600, +300, +5, + -600, +300, +5, -600, +300, +5 + }, // s + {1, 1, 0, 0, 0}, // so + { 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -600, -300, -5, -600, -300, -5, -600, -300, -5, + -600, -300, -5, -600, -300, -2, + -600, -300, +2, -600, -300, +5, -600, -300, +5, + -600, -300, +5, -600, -300, +5 + }, // o + {1, 1, 0, 0, 0}, // no + { 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +600, -300, -5, +600, -300, -5, +600, -300, -5, + +600, -300, -5, +600, -300, -2, + +600, -300, +2, +600, -300, +5, +600, -300, +5, + +600, -300, +5, +600, -300, +5 + }, // n + {1, 1, 0, 0, 0}, // ne + }, + { 15, SOUND_HOP, -1, -1, -1, + SOUND_JUMP, -1, -1, -1, -1, -1, -1, -1, -1, -1, + SOUND_COUPTOC + }, + }, + { + ACTION_JUMP3, + CHBLUPI, + { + { 20, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 106, 106, 106, 106 + }, // e + {1, 6}, // se + { 20, 133, 133, 133, 133, 133, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 133, 133, 133, 133 + }, // s + {1, 18}, // so + { 20, 134, 134, 134, 134, 134, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 134, 134, 134, 134 + }, // o + {1, 30}, // no + { 20, 135, 135, 135, 135, 135, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 135, 135, 135, 135 + }, // n + {1, 42}, // ne + }, + { + { 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +600, +300, -5, +600, +300, -5, +600, +300, -5, + +600, +300, -5, +600, +300, -5, +600, +300, -5, + +600, +300, -2, +600, +300, 0, +600, +300, +2, + +600, +300, +5, +600, +300, +5, +600, +300, +5, + +600, +300, +5, +600, +300, +5, +600, +300, +5 + }, // e + {1, 1, 0, 0, 0}, // se + { 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -600, +300, -5, -600, +300, -5, -600, +300, -5, + -600, +300, -5, -600, +300, -5, -600, +300, -5, + -600, +300, -2, -600, +300, 0, -600, +300, +2, + -600, +300, +5, -600, +300, +5, -600, +300, +5, + -600, +300, +5, -600, +300, +5, -600, +300, +5 + }, // s + {1, 1, 0, 0, 0}, // so + { 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -600, -300, -5, -600, -300, -5, -600, -300, -5, + -600, -300, -5, -600, -300, -5, -600, -300, -5, + -600, -300, -2, -600, -300, 0, -600, -300, +2, + -600, -300, +5, -600, -300, +5, -600, -300, +5, + -600, -300, +5, -600, -300, +5, -600, -300, +5 + }, // o + {1, 1, 0, 0, 0}, // no + { 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +600, -300, -5, +600, -300, -5, +600, -300, -5, + +600, -300, -5, +600, -300, -5, +600, -300, -5, + +600, -300, -2, +600, -300, 0, +600, -300, +2, + +600, -300, +5, +600, -300, +5, +600, -300, +5, + +600, -300, +5, +600, -300, +5, +600, -300, +5 + }, // n + {1, 1, 0, 0, 0}, // ne + }, + { 20, SOUND_HOP, -1, -1, -1, + SOUND_JUMP, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + SOUND_COUPTOC + }, + }, + { + ACTION_JUMP4, + CHBLUPI, + { + { 25, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 106, 106, 106, 106 + }, // e + {1, 6}, // se + { 25, 133, 133, 133, 133, 133, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 137, 133, 133, 133, 133 + }, // s + {1, 18}, // so + { 25, 134, 134, 134, 134, 134, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, + 138, 134, 134, 134, 134 + }, // o + {1, 30}, // no + { 25, 135, 135, 135, 135, 135, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 135, 135, 135, 135 + }, // n + {1, 42}, // ne + }, + { + { 25, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +600, +300, -5, +600, +300, -5, +600, +300, -5, + +600, +300, -5, +600, +300, -5, +600, +300, -5, + +600, +300, -5, +600, +300, -5, +600, +300, -5, + +600, +300, -2, +600, +300, +2, + +600, +300, +5, +600, +300, +2, +600, +300, +5, + +600, +300, +5, +600, +300, +5, +600, +300, +5, + +600, +300, +5, +600, +300, +5, +600, +300, +5 + }, // e + {1, 1, 0, 0, 0}, // se + { 25, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -600, +300, -5, -600, +300, -5, -600, +300, -5, + -600, +300, -5, -600, +300, -5, -600, +300, -5, + -600, +300, -5, -600, +300, -5, -600, +300, -5, + -600, +300, -2, -600, +300, +2, + -600, +300, +5, -600, +300, +5, -600, +300, +5, + -600, +300, +5, -600, +300, +5, -600, +300, +5, + -600, +300, +5, -600, +300, +5, -600, +300, +5 + }, // s + {1, 1, 0, 0, 0}, // so + { 25, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -600, -300, -5, -600, -300, -5, -600, -300, -5, + -600, -300, -5, -600, -300, -5, -600, -300, -5, + -600, -300, -5, -600, -300, -5, -600, -300, -5, + -600, -300, -2, -600, -300, +2, + -600, -300, +5, -600, -300, +5, -600, -300, +5, + -600, -300, +5, -600, -300, +5, -600, -300, +5, + -600, -300, +5, -600, -300, +5, -600, -300, +5 + }, // o + {1, 1, 0, 0, 0}, // no + { 25, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +600, -300, -5, +600, -300, -5, +600, -300, -5, + +600, -300, -5, +600, -300, -5, +600, -300, -5, + +600, -300, -5, +600, -300, -5, +600, -300, -5, + +600, -300, -2, +600, -300, +2, + +600, -300, +5, +600, -300, +5, +600, -300, +5, + +600, -300, +5, +600, -300, +5, +600, -300, +5, + +600, -300, +5, +600, -300, +5, +600, -300, +5 + }, // n + {1, 1, 0, 0, 0}, // ne + }, + { 25, SOUND_HOP, -1, -1, -1, + SOUND_JUMP, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, + SOUND_COUPTOC + }, + }, + { + ACTION_JUMP5, + CHBLUPI, + { + { 30, 106, 106, 106, 106, 106, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 106, 106, 106, 106 + }, // e + {1, 6}, // se + { 30, 133, 133, 133, 133, 133, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 133, 133, 133, 133 + }, // s + {1, 18}, // so + { 30, 134, 134, 134, 134, 134, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 134, 134, 134, 134 + }, // o + {1, 30}, // no + { 30, 135, 135, 135, 135, 135, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, + 139, 139, 139, 139, 139, 139, 135, 135, 135, 135 + }, // n + {1, 42}, // ne + }, + { + { 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +600, +300, -5, +600, +300, -5, +600, +300, -5, + +600, +300, -5, +600, +300, -5, +600, +300, -5, + +600, +300, -5, +600, +300, -5, +600, +300, -5, + +600, +300, -5, +600, +300, -2, +600, +300, -2, + +600, +300, 0, +600, +300, +2, +600, +300, +2, + +600, +300, +5, +600, +300, +2, +600, +300, +5, + +600, +300, +5, +600, +300, +5, +600, +300, +5, + +600, +300, +5, +600, +300, +5, +600, +300, +5, + +600, +300, +5 + }, // e + {1, 1, 0, 0, 0}, // se + { 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -600, +300, -5, -600, +300, -5, -600, +300, -5, + -600, +300, -5, -600, +300, -5, -600, +300, -5, + -600, +300, -5, -600, +300, -5, -600, +300, -5, + -600, +300, -5, -600, +300, -2, -600, +300, -2, + -600, +300, 0, -600, +300, +2, -600, +300, +2, + -600, +300, +5, -600, +300, +5, -600, +300, +5, + -600, +300, +5, -600, +300, +5, -600, +300, +5, + -600, +300, +5, -600, +300, +5, -600, +300, +5, + -600, +300, +5 + }, // s + {1, 1, 0, 0, 0}, // so + { 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -600, -300, -5, -600, -300, -5, -600, -300, -5, + -600, -300, -5, -600, -300, -5, -600, -300, -5, + -600, -300, -5, -600, -300, -5, -600, -300, -5, + -600, -300, -5, -600, -300, -2, -600, -300, -2, + -600, -300, 0, -600, -300, +2, -600, -300, +2, + -600, -300, +5, -600, -300, +5, -600, -300, +5, + -600, -300, +5, -600, -300, +5, -600, -300, +5, + -600, -300, +5, -600, -300, +5, -600, -300, +5, + -600, -300, +5 + }, // o + {1, 1, 0, 0, 0}, // no + { 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +600, -300, -5, +600, -300, -5, +600, -300, -5, + +600, -300, -5, +600, -300, -5, +600, -300, -5, + +600, -300, -5, +600, -300, -5, +600, -300, -5, + +600, -300, -5, +600, -300, -2, +600, -300, -2, + +600, -300, 0, +600, -300, +2, +600, -300, +2, + +600, -300, +5, +600, -300, +5, +600, -300, +5, + +600, -300, +5, +600, -300, +5, +600, -300, +5, + +600, -300, +5, +600, -300, +5, +600, -300, +5, + +600, -300, +5 + }, // n + {1, 1, 0, 0, 0}, // ne + }, + { 30, SOUND_HOP, -1, -1, -1, + SOUND_JUMP, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + SOUND_COUPTOC + }, + }, + { + ACTION_SLIDE, + CHBLUPI, + { + {8, 48, 49, 50, 51, 52, 53, 54, 55}, // e + {8, 49, 50, 51, 52, 53, 54, 55, 48}, // se + {8, 50, 51, 52, 53, 54, 55, 48, 49}, // s + {8, 51, 52, 53, 54, 55, 48, 49, 50}, // so + {8, 52, 53, 54, 55, 48, 49, 50, 51}, // o + {8, 53, 54, 55, 48, 49, 50, 51, 52}, // no + {8, 54, 55, 48, 49, 50, 51, 52, 53}, // n + {8, 55, 48, 49, 50, 51, 52, 53, 54}, // ne + }, + { + {10, 1, +300, +150, 0}, // e + {15, 1, 0, +200, 0}, // se + {10, 1, -300, +150, 0}, // s + {15, 1, -400, 0, 0}, // so + {10, 1, -300, -150, 0}, // o + {15, 1, 0, -200, 0}, // no + {10, 1, +300, -150, 0}, // n + {15, 1, +400, 0, 0}, // ne + }, + {0}, + }, + { + ACTION_BUILD, + CHBLUPI, + { + {1, 100}, // e + {1, 100}, // se + {4, 103, 104, 105, 105}, // s + {1, 100}, // so + {4, 100, 101, 102, 102}, // o + {1, 100}, // no + {1, 100}, // n + {1, 100}, // ne + }, + { + {40, 1, 0, 0, 0}, // e + {40, 1, 0, 0, 0}, // se + {40, 1, 0, 0, 0}, // s + {40, 1, 0, 0, 0}, // so + {40, 1, 0, 0, 0}, // o + {40, 1, 0, 0, 0}, // no + {40, 1, 0, 0, 0}, // n + {40, 1, 0, 0, 0}, // ne + }, + { 40, -1, -1, SOUND_COUPTOC, -1, -1, -1, SOUND_COUPTOC, -1, + -1, -1, SOUND_COUPTOC, -1, -1, -1, SOUND_COUPTOC, -1, + -1, -1, SOUND_COUPTOC, -1, -1, -1, SOUND_COUPTOC, -1, + -1, -1, SOUND_COUPTOC, -1, -1, -1, SOUND_COUPTOC, -1, + -1, -1, SOUND_COUPTOC, -1, -1, -1, SOUND_COUPTOC, -1 + }, + }, + { + ACTION_BUILDBREF, + CHBLUPI, + { + {1, 100}, // e + {1, 100}, // se + {4, 103, 104, 105, 105}, // s + {1, 100}, // so + {4, 100, 101, 102, 102}, // o + {1, 100}, // no + {1, 100}, // n + {1, 100}, // ne + }, + { + {40, 1, 0, 0, 0}, // e + {40, 1, 0, 0, 0}, // se + {40, 1, 0, 0, 0}, // s + {40, 1, 0, 0, 0}, // so + {40, 1, 0, 0, 0}, // o + {40, 1, 0, 0, 0}, // no + {40, 1, 0, 0, 0}, // n + {40, 1, 0, 0, 0}, // ne + }, + { 40, -1, -1, SOUND_COUPBREF, -1, -1, -1, SOUND_COUPBREF, -1, + -1, -1, SOUND_COUPBREF, -1, -1, -1, SOUND_COUPBREF, -1, + -1, -1, SOUND_COUPBREF, -1, -1, -1, SOUND_COUPBREF, -1, + -1, -1, SOUND_COUPBREF, -1, -1, -1, SOUND_COUPBREF, -1, + -1, -1, SOUND_COUPBREF, -1, -1, -1, SOUND_COUPBREF, -1 + }, + }, + { + ACTION_BUILDSEC, + CHBLUPI, + { + {1, 100}, // e + {1, 100}, // se + {4, 103, 104, 105, 105}, // s + {1, 100}, // so + {4, 100, 101, 102, 102}, // o + {1, 100}, // no + {1, 100}, // n + {1, 100}, // ne + }, + { + {40, 1, 0, 0, 0}, // e + {40, 1, 0, 0, 0}, // se + {40, 1, 0, 0, 0}, // s + {40, 1, 0, 0, 0}, // so + {40, 1, 0, 0, 0}, // o + {40, 1, 0, 0, 0}, // no + {40, 1, 0, 0, 0}, // n + {40, 1, 0, 0, 0}, // ne + }, + { 40, -1, -1, SOUND_COUPSEC, -1, -1, -1, SOUND_COUPSEC, -1, + -1, -1, SOUND_COUPSEC, -1, -1, -1, SOUND_COUPSEC, -1, + -1, -1, SOUND_COUPSEC, -1, -1, -1, SOUND_COUPSEC, -1, + -1, -1, SOUND_COUPSEC, -1, -1, -1, SOUND_COUPSEC, -1, + -1, -1, SOUND_COUPSEC, -1, -1, -1, SOUND_COUPSEC, -1 + }, + }, + { + ACTION_BUILDSOURD, + CHBLUPI, + { + {1, 100}, // e + {1, 100}, // se + {4, 103, 104, 105, 105}, // s + {1, 100}, // so + {4, 100, 101, 102, 102}, // o + {1, 100}, // no + {1, 100}, // n + {1, 100}, // ne + }, + { + {40, 1, 0, 0, 0}, // e + {40, 1, 0, 0, 0}, // se + {40, 1, 0, 0, 0}, // s + {40, 1, 0, 0, 0}, // so + {40, 1, 0, 0, 0}, // o + {40, 1, 0, 0, 0}, // no + {40, 1, 0, 0, 0}, // n + {40, 1, 0, 0, 0}, // ne + }, + { 40, -1, -1, SOUND_COUPSOURD, -1, -1, -1, SOUND_COUPSOURD, -1, + -1, -1, SOUND_COUPSOURD, -1, -1, -1, SOUND_COUPSOURD, -1, + -1, -1, SOUND_COUPSOURD, -1, -1, -1, SOUND_COUPSOURD, -1, + -1, -1, SOUND_COUPSOURD, -1, -1, -1, SOUND_COUPSOURD, -1, + -1, -1, SOUND_COUPSOURD, -1, -1, -1, SOUND_COUPSOURD, -1 + }, + }, + { + ACTION_BUILDPIERRE, + CHBLUPI, + { + {1, 100}, // e + {1, 100}, // se + {4, 103, 104, 105, 105}, // s + {1, 100}, // so + {4, 100, 101, 102, 102}, // o + {1, 100}, // no + {1, 100}, // n + {1, 100}, // ne + }, + { + {40, 1, 0, 0, 0}, // e + {40, 1, 0, 0, 0}, // se + {40, 1, 0, 0, 0}, // s + {40, 1, 0, 0, 0}, // so + {40, 1, 0, 0, 0}, // o + {40, 1, 0, 0, 0}, // no + {40, 1, 0, 0, 0}, // n + {40, 1, 0, 0, 0}, // ne + }, + { 40, -1, -1, SOUND_COUPPIERRE, -1, -1, -1, SOUND_COUPPIERRE, -1, + -1, -1, SOUND_COUPPIERRE, -1, -1, -1, SOUND_COUPPIERRE, -1, + -1, -1, SOUND_COUPPIERRE, -1, -1, -1, SOUND_COUPPIERRE, -1, + -1, -1, SOUND_COUPPIERRE, -1, -1, -1, SOUND_COUPPIERRE, -1, + -1, -1, SOUND_COUPPIERRE, -1, -1, -1, SOUND_COUPPIERRE, -1 + }, + }, + { + ACTION_PICKAXE, + CHBLUPI, + { + { 16 + 4 + 16 + 4, + 93, 93, 94, 94, 95, 95, 94, 94, 93, 93, 94, 94, 95, 95, 94, 94, + 93, 93, 96, 96, + 97, 97, 98, 98, 99, 99, 98, 98, 97, 97, 98, 98, 99, 99, 98, 98, + 97, 97, 96, 96 + }, + {0} + }, + { + { (16 + 4 + 16 + 4) * 1, 1, 0, 0, 0}, + }, + { 16 + 4 + 16 + 4, -1, -1, -1, -1, SOUND_COUPTERRE, -1, -1, -1, + -1, -1, -1, -1, SOUND_COUPTERRE, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, SOUND_COUPTERRE, -1, -1, -1, + -1, -1, -1, -1, SOUND_COUPTERRE, -1, -1, -1, + -1, -1, -1, -1 + }, + }, + { + ACTION_PIOCHESOURD, + CHBLUPI, + { + { 16 + 4 + 16 + 4, + 93, 93, 94, 94, 95, 95, 94, 94, 93, 93, 94, 94, 95, 95, 94, 94, + 93, 93, 96, 96, + 97, 97, 98, 98, 99, 99, 98, 98, 97, 97, 98, 98, 99, 99, 98, 98, + 97, 97, 96, 96 + }, + {0} + }, + { + { (16 + 4 + 16 + 4) * 1, 1, 0, 0, 0}, + }, + { 16 + 4 + 16 + 4, -1, -1, -1, -1, SOUND_COUPSOURD, -1, -1, -1, + -1, -1, -1, -1, SOUND_COUPSOURD, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, SOUND_COUPSOURD, -1, -1, -1, + -1, -1, -1, -1, SOUND_COUPSOURD, -1, -1, -1, + -1, -1, -1, -1 + }, + }, + { + ACTION_PIOCHEPIERRE, + CHBLUPI, + { + { 16 + 4 + 16 + 4, + 93, 93, 94, 94, 95, 95, 94, 94, 93, 93, 94, 94, 95, 95, 94, 94, + 93, 93, 96, 96, + 97, 97, 98, 98, 99, 99, 98, 98, 97, 97, 98, 98, 99, 99, 98, 98, + 97, 97, 96, 96 + }, + {0} + }, + { + { (16 + 4 + 16 + 4) * 1, 1, 0, 0, 0}, + }, + { 16 + 4 + 16 + 4, -1, -1, -1, -1, SOUND_COUPPIERRE, -1, -1, -1, + -1, -1, -1, -1, SOUND_COUPPIERRE, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, SOUND_COUPPIERRE, -1, -1, -1, + -1, -1, -1, -1, SOUND_COUPPIERRE, -1, -1, -1, + -1, -1, -1, -1 + }, + }, + { + ACTION_ARROSE, + CHBLUPI, + { + {10, 286, 286, 287, 287, 287, 287, 286, 286, 287, 287}, + {0} + }, + { + {40, 1, 0, 0, 0}, + }, + { 20, SOUND_ARROSE, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }, + }, + { + ACTION_BECHE, + CHBLUPI, + { + { 20, 288, 288, 288, 289, 289, 288, 288, 289, 289, 289, + 289, 289, 288, 288, 288, 288, 289, 289, 289, 289 + }, + {0} + }, + { + {40, 1, 0, 0, 0}, + }, + { 20, -1, -1, -1, SOUND_BECHE, -1, -1, -1, SOUND_BECHE, -1, -1, + -1, -1, -1, -1, -1, -1, SOUND_BECHE, -1, -1, -1 + }, + }, + { + ACTION_SAW, + CHBLUPI, + { + {1, 100}, // e + {1, 100}, // se + {8, 107, 108, 108, 109, 109, 108, 108, 107}, // s + {1, 100}, // so + {1, 100}, // o + {1, 100}, // no + {1, 100}, // n + {1, 100}, // ne + }, + { + {40, 1, 0, 0, 0}, // e + {40, 1, 0, 0, 0}, // se + {40, 1, 0, 0, 0}, // s + {40, 1, 0, 0, 0}, // so + {40, 1, 0, 0, 0}, // o + {40, 1, 0, 0, 0}, // no + {40, 1, 0, 0, 0}, // n + {40, 1, 0, 0, 0}, // ne + }, + { 40, -1, -1, -1, SOUND_SAW, -1, -1, -1, -1, + -1, -1, -1, SOUND_SAW, -1, -1, -1, -1, + -1, -1, -1, SOUND_SAW, -1, -1, -1, -1, + -1, -1, -1, SOUND_SAW, -1, -1, -1, -1, + -1, -1, -1, SOUND_SAW, -1, -1, -1, -1 + }, + }, + { + ACTION_CUEILLE1, + CHBLUPI, + { + { 20, 48, 194, 194, 194, 196, 196, 196, 196, 194, 194, + 194, 194, 196, 196, 196, 196, 48, 48, 48, 48 + }, // e + {1, 49}, // se + { 20, 50, 195, 195, 195, 197, 197, 197, 197, 195, 195, + 195, 195, 197, 197, 197, 197, 50, 50, 50, 50 + }, // s + {1, 51}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {1, 55}, // ne + }, + { + {20, 1, 0, 0, 0}, // e + {20, 1, 0, 0, 0}, // se + {20, 1, 0, 0, 0}, // s + {20, 1, 0, 0, 0}, // so + {20, 1, 0, 0, 0}, // o + {20, 1, 0, 0, 0}, // no + {20, 1, 0, 0, 0}, // n + {20, 1, 0, 0, 0}, // ne + }, + {0}, + }, + { + ACTION_CUEILLE2, + CHBLUPI, + { + { 20, 48, 194, 194, 194, 198, 198, 198, 198, 194, 194, + 194, 194, 198, 198, 198, 198, 48, 48, 48, 48 + }, // e + {1, 49}, // se + { 20, 50, 195, 195, 195, 199, 199, 199, 199, 195, 195, + 195, 195, 199, 199, 199, 199, 50, 50, 50, 50 + }, // s + {1, 51}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {1, 55}, // ne + }, + { + {20, 1, 0, 0, 0}, // e + {20, 1, 0, 0, 0}, // se + {20, 1, 0, 0, 0}, // s + {20, 1, 0, 0, 0}, // so + {20, 1, 0, 0, 0}, // o + {20, 1, 0, 0, 0}, // no + {20, 1, 0, 0, 0}, // n + {20, 1, 0, 0, 0}, // ne + }, + {0}, + }, + { + ACTION_CUEILLE3, + CHBLUPI, + { + { 20, 48, 194, 194, 194, 306, 306, 306, 306, 194, 194, + 194, 194, 306, 306, 306, 306, 48, 48, 48, 48 + }, // e + {1, 49}, // se + { 20, 50, 195, 195, 195, 307, 307, 307, 307, 195, 195, + 195, 195, 307, 307, 307, 307, 50, 50, 50, 50 + }, // s + {1, 51}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {1, 55}, // ne + }, + { + {20, 1, 0, 0, 0}, // e + {20, 1, 0, 0, 0}, // se + {20, 1, 0, 0, 0}, // s + {20, 1, 0, 0, 0}, // so + {20, 1, 0, 0, 0}, // o + {20, 1, 0, 0, 0}, // no + {20, 1, 0, 0, 0}, // n + {20, 1, 0, 0, 0}, // ne + }, + {0}, + }, + { + ACTION_LABO, + CHBLUPI, + { + {1, 48}, + {0} + }, + { + {90, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_MECHE, + CHBLUPI, + { + { 36, 106, 106, 106, 106, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, + 110, 110, 110, 110, 110, 110 + }, + {0} + }, + { + {36, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_DYNAMITE, + CHBLUPI, + { + {1, 48}, + {0} + }, + { + {12, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_DELAY, + CHBLUPI, + { + {1, 48}, // e + {1, 49}, // se + {1, 50}, // s + {1, 51}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {1, 55}, // ne + }, + { + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_BRIDGE, + CHBLUPI, + { + {8, 48, 49, 50, 51, 52, 53, 54, 55}, // e + {1, 49}, // se + {8, 50, 49, 48, 55, 54, 53, 52, 51}, // s + {1, 51}, // so + {8, 52, 51, 50, 49, 48, 55, 54, 53}, // o + {1, 53}, // no + {8, 54, 55, 48, 49, 50, 51, 52, 53}, // n + {1, 55}, // ne + }, + { + {30, 1, 0, 0, 0}, // e + {30, 1, 0, 0, 0}, // se + {30, 1, 0, 0, 0}, // s + {30, 1, 0, 0, 0}, // so + {30, 1, 0, 0, 0}, // o + {30, 1, 0, 0, 0}, // no + {30, 1, 0, 0, 0}, // n + {30, 1, 0, 0, 0}, // ne + }, + { 30, SOUND_HOP, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }, + }, + { + ACTION_CARRY, + CHBLUPI, + { + { 2 + 6 + 15, 106, 106, 48, 48, 48, 48, 48, 48, 106, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 + }, + {1, 49}, + { 2 + 6 + 15, 133, 133, 50, 50, 50, 50, 50, 50, 133, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50 + }, + {1, 51}, + {1, 52}, + {1, 53}, + {1, 54}, + {1, 55}, + }, + { + { 2 + 6 + 15, 2 + 6 + 15, + 0, 0, 0, 0, 0, 0, + 0, 0, -8, 0, 0, -5, 0, 0, -2, 0, 0, +2, 0, 0, +5, 0, 0, +8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + {1, 1, 0, 0, 0}, + { 2 + 6 + 15, 2 + 6 + 15, + 0, 0, 0, 0, 0, 0, + 0, 0, -8, 0, 0, -5, 0, 0, -2, 0, 0, +2, 0, 0, +5, 0, 0, +8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + }, + { 2 + 6 + 15, SOUND_HOP, -1, -1, -1, -1, -1, -1, -1, + SOUND_JUMP, -1, -1, -1, -1, -1, -1, -1, -1, + SOUND_COUPTOC, -1, -1, -1, -1, -1 + }, + }, + { + ACTION_DROP, + CHBLUPI, + { + {10, 106, 106, 106, 106, 106, 48, 48, 48, 48, 48}, + {1, 49}, + {10, 133, 133, 133, 133, 133, 50, 50, 50, 50, 50}, + {1, 51}, + {1, 52}, + {1, 53}, + {1, 54}, + {1, 55}, + }, + { + {10, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {10, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + }, + { 10, SOUND_HOP, -1, -1, -1, -1, -1, -1, -1, -1, + SOUND_COUPTERRE, + }, + }, + { + ACTION_BURN, + CHBLUPI, + { + {8, 48, 49, 50, 51, 52, 53, 54, 55}, + {0} + }, + { + {40, 1, 0, 0, -10}, + }, + {0}, + }, + { + ACTION_TCHAO, + CHBLUPI, + { + { 48, 308, 308, 308, 308, 308, 308, 308, 308, + 308, 308, 308, 308, 309, 309, 309, 309, + 309, 309, 309, 309, 309, 309, 309, 309, + 310, 310, 310, 310, 310, 310, 311, 311, + 311, 311, 311, 311, 312, 312, 312, 312, + 312, 312, 313, 313, 313, 313, 313, 313 + }, + {0} + }, + { + {48, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_ELECTRO, + CHBLUPI, + { + {4, 270, 271, 272, 271}, + {0} + }, + { + {60, 1, 0, 0, 0}, + }, + { 30, SOUND_BURN, -1, -1, -1, -1, -1, -1, -1, -1, -1, + SOUND_BURN, -1, -1, -1, -1, -1, -1, -1, -1, -1, + SOUND_BURN, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }, + }, + { + ACTION_GRILL1, + CHBLUPI, + { + { 40, 273, 273, 273, 273, 273, 273, 273, 273, 273, 274, + 273, 273, 273, 274, 273, 273, 273, 273, 273, 273, + 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, + 273, 274, 273, 273, 273, 273, 273, 273, 273, 273 + }, + {0} + }, + { + {40, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_GRILL2, + CHBLUPI, + { + { 12, 275, 273, 275, + 276, 275, 276, + 277, 276, 277, + 278, 277, 278 + }, + {0} + }, + { + {12, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_GRILL3, + CHBLUPI, + { + { 50, 279, 280, 279, 280, 280, 279, 280, 279, 279, 280, + 280, 280, 279, 280, 279, 279, 280, 279, 280, 280, + 279, -1, 279, 280, 280, 279, 280, 279, 279, 280, + 279, 280, 279, 280, -1, 280, 279, 280, -1, 280, + 279, -1, 279, 280, -1, 279, -1, 279, -1, 280 + }, + {0} + }, + { + {50, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_EAT, + CHBLUPI, + { + { 39, 113, 114, 114, 113, 113, 113, 114, 114, 113, 114, + 113, 114, 114, 113, 113, 113, 114, 114, 113, 114, + 113, 114, 114, 113, 113, 113, 114, 114, 113, 114, + 48, 48, 48, 48, 48, 48, 48, 48, 48 + }, + {0} + }, + { + {39, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_DRINK, + CHBLUPI, + { + {1, 193}, + {0} + }, + { + {40, 2, 0, 0, -3, 0, 0, +3}, + }, + {0}, + }, + { + ACTION_HAPPY, + CHBLUPI, + { + {1, 48}, // e + {1, 49}, // se + {1, 50}, // s + {1, 51}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {1, 55}, // ne + }, + { + {20, 4, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, +2}, + {20, 4, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, +2}, + {20, 4, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, +2}, + {20, 4, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, +2}, + {20, 4, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, +2}, + {20, 4, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, +2}, + {20, 4, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, +2}, + {20, 4, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, +2}, + }, + {0}, + }, + { + ACTION_BORN, + CHBLUPI, + { + { 20 + 9, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, + 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, + 48, 49, 50, 51, 52, 53, 54, 55, 48 + }, + {0} + }, + { + { 20 + 9, 20 + 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -10, 0, 0, -10, 0, 0, -8, 0, 0, -3, + 0, 0, +3, 0, 0, +8, 0, 0, +10, 0, 0, +10, + 0, 0, 0 + }, + }, + { 20 + 9, SOUND_BORN, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + SOUND_BORN, -1, -1, -1, -1, -1, -1, -1, + SOUND_COUPTOC + }, + }, + { + ACTION_TELEPORTE1, + CHBLUPI, + { + { 16, 318, 318, 319, 319, 318, 319, 319, 318, + 318, 319, 319, 318, 318, 319, 319, 318 + }, + {0} + }, + { + {32, 4, -100, 0, 0, +100, 0, 0, +100, 0, 0, -100, 0, 0}, + }, + {0}, + }, + { + ACTION_TELEPORTE2, + CHBLUPI, + { + { 16, 320, 318, 319, 321, 318, 320, 319, 318, + 318, 321, 319, 318, 320, 319, 321, 318 + }, + {0} + }, + { + {32, 4, -100, 0, 0, +100, 0, 0, +100, 0, 0, -100, 0, 0}, + }, + {0}, + }, + { + ACTION_TELEPORTE3, + CHBLUPI, + { + { 32, 320, 320, 321, 321, 320, 321, 321, 320, + 320, 321, 321, 320, -1, 321, 321, 320, + 320, -1, 321, 321, -1, 321, 321, -1, + 320, -1, -1, 320, -1, 321, -1, 320 + }, + {0} + }, + { + {32, 4, 0, 0, 0, 0, 0, -1, 0, 0, +1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_MISC1, // hausse les épaules + CHBLUPI, + { + {1, 140}, // e + {1, 141}, // se + {1, 142}, // s + {1, 143}, // so + {1, 144}, // o + {1, 145}, // no + {1, 146}, // n + {1, 147}, // ne + }, + { + {3, 1, 0, 0, 0}, + {3, 1, 0, 0, 0}, + {3, 1, 0, 0, 0}, + {3, 1, 0, 0, 0}, + {3, 1, 0, 0, 0}, + {3, 1, 0, 0, 0}, + {3, 1, 0, 0, 0}, + {3, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_MISC2, // grat-grat + CHBLUPI, + { + {6, 154, 154, 154, 154, 155, 155}, // e + {1, 49}, // se + {6, 156, 156, 156, 156, 157, 157}, // s + {1, 51}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {6, 158, 158, 158, 158, 159, 159}, // ne + }, + { + {24, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + {24, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + {24, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_MISC3, // yoyo + CHBLUPI, + { + {8, 148, 148, 149, 149, 150, 150, 149, 149}, // e + {1, 49}, // se + {8, 151, 151, 152, 152, 153, 153, 152, 152}, // s + {1, 51}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {1, 55}, // ne + }, + { + {32, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + {32, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_MISC4, // ferme les yeux + CHBLUPI, + { + {1, 281}, // e + {1, 282}, // se + {1, 283}, // s + {1, 284}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {1, 285}, // ne + }, + { + {2, 1, 0, 0, 0}, + {2, 1, 0, 0, 0}, + {2, 1, 0, 0, 0}, + {2, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {2, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_MISC5, // ohé + CHBLUPI, + { + {8, 110, 110, 111, 111, 110, 110, 112, 112}, + {1, 49}, // se + {1, 50}, // s + {1, 51}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {1, 55}, // ne + }, + { + {16, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_MISC6, // diabolo + CHBLUPI, + { + {1, 48}, // e + {1, 49}, // se + {6, 361, 362, 363, 364, 365, 363}, // s + {1, 51}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {1, 55}, // ne + }, + { + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + {36, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + { 1, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_MISC1f, + CHBLUPI, + { + {12, 69, 69, 69, 72, 72, 72, 69, 69, 69, 90, 90, 90}, // e + {12, 72, 72, 72, 75, 75, 75, 72, 72, 72, 69, 69, 69}, // se + {12, 75, 75, 75, 78, 78, 78, 75, 75, 75, 72, 72, 72}, // s + {12, 78, 78, 78, 81, 81, 81, 78, 78, 78, 75, 75, 75}, // so + {12, 81, 81, 81, 84, 84, 84, 81, 81, 81, 78, 78, 78}, // o + {12, 84, 84, 84, 87, 87, 87, 84, 84, 84, 81, 81, 81}, // no + {12, 87, 87, 87, 90, 90, 90, 87, 87, 87, 84, 84, 84}, // n + {12, 90, 90, 90, 69, 69, 69, 90, 90, 90, 87, 87, 87}, // ne + }, + { + {12, 1, 0, 0, 0}, + {12, 1, 0, 0, 0}, + {12, 1, 0, 0, 0}, + {12, 1, 0, 0, 0}, + {12, 1, 0, 0, 0}, + {12, 1, 0, 0, 0}, + {12, 1, 0, 0, 0}, + {12, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_ARMOROPEN, + CHBLUPI, + { + {1, 346}, + {0} + }, + { + {15, 1, 0, 0, 0}, + }, + { 15, SOUND_ARMUREOPEN, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1 + }, + }, + { + ACTION_ARMORCLOSE, + CHBLUPI, + { + {1, 346}, + {0} + }, + { + {15, 1, 0, 0, 0}, + }, + { 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, SOUND_ARMURECLOSE + }, + }, + + // Disciple : + + { + ACTION_D_STOP, + CHBLUPI, + { + {1, 48}, // e + {1, 49}, // se + {1, 50}, // s + {1, 51}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {1, 55}, // ne + }, + { + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_D_WALK, + CHBLUPI, + { + {1, 48}, // e + {1, 49}, // se + {1, 50}, // s + {1, 51}, // so + {1, 52}, // o + {1, 53}, // no + {1, 54}, // n + {1, 55}, // ne + }, + { + {5, 1, +600, +300, 0}, + {7, 1, 0, +429, 0}, + {5, 1, -600, +300, 0}, + {7, 1, -858, 0, 0}, + {5, 1, -600, -300, 0}, + {7, 1, 0, -429, 0}, + {5, 1, +600, -300, 0}, + {7, 1, +858, 0, 0}, + }, + {0}, + }, + { + ACTION_D_BUILD, + CHBLUPI, + { + {4, 290, 304, 290, 292}, // e + {4, 292, 290, 292, 294}, // se + {4, 294, 292, 294, 296}, // s + {4, 296, 294, 296, 298}, // so + {4, 298, 296, 298, 300}, // o + {4, 300, 298, 300, 302}, // no + {4, 302, 300, 302, 304}, // n + {4, 304, 302, 304, 290}, // ne + }, + { + {40, 1, 0, 0, 0}, // e + {40, 1, 0, 0, 0}, // se + {40, 1, 0, 0, 0}, // s + {40, 1, 0, 0, 0}, // so + {40, 1, 0, 0, 0}, // o + {40, 1, 0, 0, 0}, // no + {40, 1, 0, 0, 0}, // n + {40, 1, 0, 0, 0}, // ne + }, + {0}, + }, + { + ACTION_D_SAW, + CHBLUPI, + { + {1, 290}, // e + {1, 292}, // se + {1, 294}, // s + {1, 296}, // so + {1, 298}, // o + {1, 300}, // no + {1, 302}, // n + {1, 304}, // ne + }, + { + {40, 4, 0, 0, -2, 0, 0, -2, 0, 0, +2, 0, 0, +2}, + {40, 4, 0, 0, -2, 0, 0, -2, 0, 0, +2, 0, 0, +2}, + {40, 4, 0, 0, -2, 0, 0, -2, 0, 0, +2, 0, 0, +2}, + {40, 4, 0, 0, -2, 0, 0, -2, 0, 0, +2, 0, 0, +2}, + {40, 4, 0, 0, -2, 0, 0, -2, 0, 0, +2, 0, 0, +2}, + {40, 4, 0, 0, -2, 0, 0, -2, 0, 0, +2, 0, 0, +2}, + {40, 4, 0, 0, -2, 0, 0, -2, 0, 0, +2, 0, 0, +2}, + {40, 4, 0, 0, -2, 0, 0, -2, 0, 0, +2, 0, 0, +2}, + }, + {0}, + }, + { + ACTION_D_ARROSE, + CHBLUPI, + { + {12, 290, 290, 290, 304, 304, 304, 290, 290, 290, 292, 292, 292}, // e + {12, 292, 292, 292, 290, 290, 290, 292, 292, 292, 294, 294, 294}, // se + {12, 294, 294, 294, 292, 292, 292, 294, 294, 294, 296, 296, 296}, // s + {12, 296, 296, 296, 294, 294, 294, 296, 296, 296, 298, 298, 298}, // so + {12, 298, 298, 298, 296, 296, 296, 298, 298, 298, 300, 300, 300}, // o + {12, 300, 300, 300, 298, 298, 298, 300, 300, 300, 302, 302, 302}, // no + {12, 302, 302, 302, 300, 300, 300, 302, 302, 302, 304, 304, 304}, // n + {12, 304, 304, 304, 302, 302, 302, 304, 304, 304, 290, 290, 290}, // ne + }, + { + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_D_BECHE, + CHBLUPI, + { + {1, 290}, // e + {1, 292}, // se + {1, 294}, // s + {1, 296}, // so + {1, 298}, // o + {1, 300}, // no + {1, 302}, // n + {1, 304}, // ne + }, + { + {40, 4, 0, 0, 0, 0, 0, -2, 0, 0, +2, 0, 0, 0}, + {40, 4, 0, 0, 0, 0, 0, -2, 0, 0, +2, 0, 0, 0}, + {40, 4, 0, 0, 0, 0, 0, -2, 0, 0, +2, 0, 0, 0}, + {40, 4, 0, 0, 0, 0, 0, -2, 0, 0, +2, 0, 0, 0}, + {40, 4, 0, 0, 0, 0, 0, -2, 0, 0, +2, 0, 0, 0}, + {40, 4, 0, 0, 0, 0, 0, -2, 0, 0, +2, 0, 0, 0}, + {40, 4, 0, 0, 0, 0, 0, -2, 0, 0, +2, 0, 0, 0}, + {40, 4, 0, 0, 0, 0, 0, -2, 0, 0, +2, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_D_PICKAXE, + CHBLUPI, + { + {8, 290, 290, 304, 304, 290, 290, 292, 292}, // e + {8, 292, 292, 290, 290, 292, 292, 294, 294}, // se + {8, 294, 294, 292, 292, 294, 294, 296, 296}, // s + {8, 296, 296, 294, 294, 296, 296, 298, 298}, // so + {8, 298, 298, 296, 296, 298, 298, 300, 300}, // o + {8, 300, 300, 298, 298, 300, 300, 302, 302}, // no + {8, 302, 302, 300, 300, 302, 302, 304, 304}, // n + {8, 304, 304, 302, 302, 304, 304, 290, 290}, // ne + }, + { + {40, 1, 0, 0, 0}, // e + {40, 1, 0, 0, 0}, // se + {40, 1, 0, 0, 0}, // s + {40, 1, 0, 0, 0}, // so + {40, 1, 0, 0, 0}, // o + {40, 1, 0, 0, 0}, // no + {40, 1, 0, 0, 0}, // n + {40, 1, 0, 0, 0}, // ne + }, + {0}, + }, + { + ACTION_D_CUEILLE1, + CHBLUPI, + { + {12, 290, 290, 290, 304, 304, 304, 290, 290, 290, 292, 292, 292}, // e + {12, 292, 292, 292, 290, 290, 290, 292, 292, 292, 294, 294, 294}, // se + {12, 294, 294, 294, 292, 292, 292, 294, 294, 294, 296, 296, 296}, // s + {12, 296, 296, 296, 294, 294, 294, 296, 296, 296, 298, 298, 298}, // so + {12, 298, 298, 298, 296, 296, 296, 298, 298, 298, 300, 300, 300}, // o + {12, 300, 300, 300, 298, 298, 298, 300, 300, 300, 302, 302, 302}, // no + {12, 302, 302, 302, 300, 300, 300, 302, 302, 302, 304, 304, 304}, // n + {12, 304, 304, 304, 302, 302, 302, 304, 304, 304, 290, 290, 290}, // ne + }, + { + {20, 1, 0, 0, 0}, // e + {20, 1, 0, 0, 0}, // se + {20, 1, 0, 0, 0}, // s + {20, 1, 0, 0, 0}, // so + {20, 1, 0, 0, 0}, // o + {20, 1, 0, 0, 0}, // no + {20, 1, 0, 0, 0}, // n + {20, 1, 0, 0, 0}, // ne + }, + {0}, + }, + { + ACTION_D_CUEILLE2, + CHBLUPI, + { + {12, 290, 290, 290, 304, 304, 304, 290, 290, 290, 292, 292, 292}, // e + {12, 292, 292, 292, 290, 290, 290, 292, 292, 292, 294, 294, 294}, // se + {12, 294, 294, 294, 292, 292, 292, 294, 294, 294, 296, 296, 296}, // s + {12, 296, 296, 296, 294, 294, 294, 296, 296, 296, 298, 298, 298}, // so + {12, 298, 298, 298, 296, 296, 296, 298, 298, 298, 300, 300, 300}, // o + {12, 300, 300, 300, 298, 298, 298, 300, 300, 300, 302, 302, 302}, // no + {12, 302, 302, 302, 300, 300, 300, 302, 302, 302, 304, 304, 304}, // n + {12, 304, 304, 304, 302, 302, 302, 304, 304, 304, 290, 290, 290}, // ne + }, + { + {20, 1, 0, 0, 0}, // e + {20, 1, 0, 0, 0}, // se + {20, 1, 0, 0, 0}, // s + {20, 1, 0, 0, 0}, // so + {20, 1, 0, 0, 0}, // o + {20, 1, 0, 0, 0}, // no + {20, 1, 0, 0, 0}, // n + {20, 1, 0, 0, 0}, // ne + }, + {0}, + }, + { + ACTION_D_MECHE, + CHBLUPI, + { + {1, 290}, // e + {1, 292}, // se + {1, 294}, // s + {1, 296}, // so + {1, 298}, // o + {1, 300}, // no + {1, 302}, // n + {1, 304}, // ne + }, + { + {36, 2, 0, 0, -2, 0, 0, +2}, + {36, 2, 0, 0, -2, 0, 0, +2}, + {36, 2, 0, 0, -2, 0, 0, +2}, + {36, 2, 0, 0, -2, 0, 0, +2}, + {36, 2, 0, 0, -2, 0, 0, +2}, + {36, 2, 0, 0, -2, 0, 0, +2}, + {36, 2, 0, 0, -2, 0, 0, +2}, + {36, 2, 0, 0, -2, 0, 0, +2}, + }, + {0}, + }, + { + ACTION_D_TCHAO, + CHBLUPI, + { + {4, 290, 304, 290, 292}, // e + {4, 292, 290, 292, 294}, // se + {4, 294, 292, 294, 296}, // s + {4, 296, 294, 296, 298}, // so + {4, 298, 296, 298, 300}, // o + {4, 300, 298, 300, 302}, // no + {4, 302, 300, 302, 304}, // n + {4, 304, 302, 304, 290}, // ne + }, + { + {8 * 6, 1, 0, 0, 0}, + {8 * 6, 1, 0, 0, 0}, + {8 * 6, 1, 0, 0, 0}, + {8 * 6, 1, 0, 0, 0}, + {8 * 6, 1, 0, 0, 0}, + {8 * 6, 1, 0, 0, 0}, + {8 * 6, 1, 0, 0, 0}, + {8 * 6, 1, 0, 0, 0}, + }, + {0}, + }, + + // Araignée : + + { + ACTION_S_STOP, + CHBLUPI, + { + {4, 116, 117, 117, 116}, // e + {4, 118, 119, 119, 118}, // se + {4, 120, 121, 121, 120}, // s + {4, 122, 123, 123, 122}, // so + {4, 124, 125, 125, 124}, // o + {4, 126, 127, 127, 126}, // no + {4, 128, 129, 129, 128}, // n + {4, 130, 131, 131, 130}, // ne + }, + { + {4, 4, 0, 0, 0, 0, 0, -5, 0, 0, +5, 0, 0, 0}, + {4, 4, 0, 0, 0, 0, 0, -5, 0, 0, +5, 0, 0, 0}, + {4, 4, 0, 0, 0, 0, 0, -5, 0, 0, +5, 0, 0, 0}, + {4, 4, 0, 0, 0, 0, 0, -5, 0, 0, +5, 0, 0, 0}, + {4, 4, 0, 0, 0, 0, 0, -5, 0, 0, +5, 0, 0, 0}, + {4, 4, 0, 0, 0, 0, 0, -5, 0, 0, +5, 0, 0, 0}, + {4, 4, 0, 0, 0, 0, 0, -5, 0, 0, +5, 0, 0, 0}, + {4, 4, 0, 0, 0, 0, 0, -5, 0, 0, +5, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_S_WALK, + CHBLUPI, + { + {10, 117, 117, 117, 117, 117, 117, 117, 117, 116, 116}, + {10, 119, 119, 119, 119, 119, 119, 119, 119, 118, 118}, + {10, 121, 121, 121, 121, 121, 121, 121, 121, 120, 120}, + {10, 123, 123, 123, 123, 123, 123, 123, 123, 122, 122}, + {10, 125, 125, 125, 125, 125, 125, 125, 125, 124, 124}, + {10, 127, 127, 127, 127, 127, 127, 127, 127, 126, 126}, + {10, 129, 129, 129, 129, 129, 129, 129, 129, 128, 128}, + {10, 131, 131, 131, 131, 131, 131, 131, 131, 130, 130}, + }, + { + { 10, 10, +300, +150, -10, +300, +150, -10, +300, +150, -10, +300, +150, -8, +300, +150, -2, + +300, +150, +2, +300, +150, +8, +300, +150, +10, +300, +150, +10, +300, +150, +10 + }, + { 10, 10, 0, +300, -10, 0, +300, -10, 0, +300, -10, 0, +300, -8, 0, +300, -2, + 0, +300, +2, 0, +300, +8, 0, +300, +10, 0, +300, +10, 0, +300, +10 + }, + { 10, 10, -300, +150, -10, -300, +150, -10, -300, +150, -10, -300, +150, -8, -300, +150, -2, + -300, +150, +2, -300, +150, +8, -300, +150, +10, -300, +150, +10, -300, +150, +10 + }, + { 10, 10, -600, 0, -10, -600, 0, -10, -600, 0, -10, -600, 0, -8, -600, 0, -2, + -600, 0, +2, -600, 0, +8, -600, 0, +10, -600, 0, +10, -600, 0, +10 + }, + { 10, 10, -300, -150, -10, -300, -150, -10, -300, -150, -10, -300, -150, -8, -300, -150, -2, + -300, -150, +2, -300, -150, +8, -300, -150, +10, -300, -150, +10, -300, -150, +10 + }, + { 10, 10, 0, -300, -10, 0, -300, -10, 0, -300, -10, 0, -300, -8, 0, -300, -2, + 0, -300, +2, 0, -300, +8, 0, -300, +10, 0, -300, +10, 0, -300, +10 + }, + { 10, 10, +300, -150, -10, +300, -150, -10, +300, -150, -10, +300, -150, -8, +300, -150, -2, + +300, -150, +2, +300, -150, +8, +300, -150, +10, +300, -150, +10, +300, -150, +10 + }, + { 10, 10, +600, 0, -10, +600, 0, -10, +600, 0, -10, +600, 0, -8, +600, 0, -2, + +600, 0, +2, +600, 0, +8, +600, 0, +10, +600, 0, +10, +600, 0, +10 + }, + }, + {10, -1, -1, -1, -1, -1, -1, -1, -1, -1, SOUND_S_JUMP}, + }, + { + ACTION_S_GRILL, + CHBLUPI, + { + { 40, 165, 165, 166, 165, 165, 166, 165, 166, 165, 165, + 166, 166, 167, 166, 167, 167, 166, 166, 167, 166, + 167, 167, 167, 168, 167, 167, 167, 168, 167, 167, + 168, 167, 168, 168, 168, 168, 167, 168, 168, 168 + }, + {0} + }, + { + {40, 1, 0, 0, 0}, + }, + { 30, SOUND_RAYON1, -1, -1, -1, -1, + SOUND_RAYON1, -1, -1, -1, -1, + SOUND_RAYON1, -1, -1, -1, -1, + SOUND_RAYON1, -1, -1, -1, -1, + SOUND_RAYON1, -1, -1, -1, -1, + SOUND_RAYON1, -1, -1, -1, -1 + }, + }, + { + ACTION_S_POISON, + CHBLUPI, + { + {8, 117, 119, 121, 123, 125, 127, 129, 131}, + {0} + }, + { + {32, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_S_DEAD1, + CHBLUPI, + { + {6, 314, 315, 316, 317, 316, 315}, + {0} + }, + { + {30, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_S_DEAD2, + CHBLUPI, + { + { 50, 314, 314, 314, 314, 314, 315, 316, 315, 315, 316, + 317, 317, 317, 316, 317, 317, 317, 317, 317, 317, + 316, 315, 314, 314, 314, 315, 316, 315, 315, 315, + 316, 316, 316, 316, 316, 316, 316, 316, 316, 316, + 316, 315, 314, 314, 314, 314, 314, 314, 317, 314 + }, + {0} + }, + { + {100, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_S_DEAD3, + CHBLUPI, + { + {1, 317}, + {0} + }, + { + {100, 1, 0, 0, 0}, + }, + {0}, + }, + + // Virus : + + { + ACTION_V_STOP, + CHBLUPI, + { + {10, 160, 161, 162, 163, 161, 160, 162, 161, 163, 162}, + {0} + }, + { + {10, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_V_WALK, + CHBLUPI, + { + {10, 160, 161, 162, 163, 161, 160, 162, 161, 163, 162}, + {10, 160, 161, 162, 163, 161, 160, 162, 161, 163, 162}, + {10, 160, 161, 162, 163, 161, 160, 162, 161, 163, 162}, + {10, 160, 161, 162, 163, 161, 160, 162, 161, 163, 162}, + {10, 160, 161, 162, 163, 161, 160, 162, 161, 163, 162}, + {10, 160, 161, 162, 163, 161, 160, 162, 161, 163, 162}, + {10, 160, 161, 162, 163, 161, 160, 162, 161, 163, 162}, + {10, 160, 161, 162, 163, 161, 160, 162, 161, 163, 162}, + }, + { + {50, 1, +60, +30, 0}, // e + {75, 1, 0, +40, 0}, // se + {50, 1, -60, +30, 0}, // s + {75, 1, -80, 0, 0}, // so + {50, 1, -60, -30, 0}, // o + {75, 1, 0, -40, 0}, // no + {50, 1, +60, -30, 0}, // n + {75, 1, +80, 0, 0}, // ne + }, + {0}, + }, + { + ACTION_V_GRILL, + CHBLUPI, + { + {5, 164, 160, 164, 164, 160}, + {0} + }, + { + {40, 1, 0, 0, 0}, + }, + { 30, SOUND_RAYON1, -1, -1, -1, -1, + SOUND_RAYON1, -1, -1, -1, -1, + SOUND_RAYON1, -1, -1, -1, -1, + SOUND_RAYON1, -1, -1, -1, -1, + SOUND_RAYON1, -1, -1, -1, -1, + SOUND_RAYON1, -1, -1, -1, -1 + }, + }, + + + // Tracks : + + { + ACTION_T_STOP, + CHBLUPI, + { + {1, 200}, // e + {1, 202}, // se + {1, 204}, // s + {1, 206}, // so + {1, 208}, // o + {1, 210}, // no + {1, 212}, // n + {1, 214}, // ne + }, + { + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_T_WALK, + CHBLUPI, + { + {1, 200}, // e + {1, 202}, // se + {1, 204}, // s + {1, 206}, // so + {1, 208}, // o + {1, 210}, // no + {1, 212}, // n + {1, 214}, // ne + }, + { + {10, 1, +300, +150, 0}, // e + {15, 1, 0, +200, 0}, // se + {10, 1, -300, +150, 0}, // s + {15, 1, -400, 0, 0}, // so + {10, 1, -300, -150, 0}, // o + {15, 1, 0, -200, 0}, // no + {10, 1, +300, -150, 0}, // n + {15, 1, +400, 0, 0}, // ne + }, + {5, SOUND_T_ENGINE, -1, -1, -1, -1}, + }, + { + ACTION_T_CRUSHED, + CHBLUPI, + { + {8, 200, 201, 201, 200, 200, 215, 215, 200}, // e + {8, 202, 203, 203, 202, 202, 201, 201, 202}, // se + {8, 204, 205, 205, 204, 204, 203, 203, 204}, // s + {8, 206, 207, 207, 206, 206, 205, 205, 206}, // so + {8, 208, 209, 209, 208, 208, 207, 207, 208}, // o + {8, 210, 211, 211, 210, 210, 209, 209, 210}, // no + {8, 212, 213, 213, 212, 212, 211, 211, 212}, // n + {8, 214, 215, 215, 214, 214, 213, 213, 214}, // ne + }, + { + {16, 1, 0, 0, 0}, + {16, 1, 0, 0, 0}, + {16, 1, 0, 0, 0}, + {16, 1, 0, 0, 0}, + {16, 1, 0, 0, 0}, + {16, 1, 0, 0, 0}, + {16, 1, 0, 0, 0}, + {16, 1, 0, 0, 0}, + }, + {0}, + }, + + // Robot : + + { + ACTION_R_STOP, + CHBLUPI, + { + {1, 216}, // e + {1, 218}, // se + {1, 220}, // s + {1, 222}, // so + {1, 224}, // o + {1, 226}, // no + {1, 228}, // n + {1, 230}, // ne + }, + { + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_R_WALK, + CHBLUPI, + { + {1, 216}, // e + {1, 218}, // se + {1, 220}, // s + {1, 222}, // so + {1, 224}, // o + {1, 226}, // no + {1, 228}, // n + {1, 230}, // ne + }, + { +#if 0 + {20, 1, +150, +75, 0}, // e + {30, 1, 0, +100, 0}, // se + {20, 1, -150, +75, 0}, // s + {30, 1, -200, 0, 0}, // so + {20, 1, -150, -75, 0}, // o + {30, 1, 0, -100, 0}, // no + {20, 1, +150, -75, 0}, // n + {30, 1, +200, 0, 0}, // ne +#else + { 20, 20, +20, +10, 0, +80, +40, 0, +140, +70, 0, +180, +90, 0, + +180, +90, 0, +180, +90, 0, +180, +90, 0, +180, +90, 0, + +180, +90, 0, +180, +90, 0, +180, +90, 0, +180, +90, 0, + +180, +90, 0, +180, +90, 0, +180, +90, 0, +180, +90, 0, + +180, +90, 0, +140, +70, 0, +80, +40, 0, +20, +10, 0 + }, + { 30, 30, 0, +10, 0, 0, +20, 0, 0, +60, 0, 0, +90, 0, 0, +120, 0, + 0, +120, 0, 0, +120, 0, 0, +120, 0, 0, +120, 0, 0, +120, 0, + 0, +120, 0, 0, +120, 0, 0, +120, 0, 0, +120, 0, 0, +120, 0, + 0, +120, 0, 0, +120, 0, 0, +120, 0, 0, +120, 0, 0, +120, 0, + 0, +120, 0, 0, +120, 0, 0, +120, 0, 0, +120, 0, 0, +120, 0, + 0, +120, 0, 0, +90, 0, 0, +60, 0, 0, +20, 0, 0, +10, 0 + }, + { 20, 20, -20, +10, 0, -80, +40, 0, -140, +70, 0, -180, +90, 0, + -180, +90, 0, -180, +90, 0, -180, +90, 0, -180, +90, 0, + -180, +90, 0, -180, +90, 0, -180, +90, 0, -180, +90, 0, + -180, +90, 0, -180, +90, 0, -180, +90, 0, -180, +90, 0, + -180, +90, 0, -140, +70, 0, -80, +40, 0, -20, +10, 0 + }, + { 30, 30, -20, 0, 0, -40, 0, 0, -120, 0, 0, -180, 0, 0, -240, 0, 0, + -240, 0, 0, -240, 0, 0, -240, 0, 0, -240, 0, 0, -240, 0, 0, + -240, 0, 0, -240, 0, 0, -240, 0, 0, -240, 0, 0, -240, 0, 0, + -240, 0, 0, -240, 0, 0, -240, 0, 0, -240, 0, 0, -240, 0, 0, + -240, 0, 0, -240, 0, 0, -240, 0, 0, -240, 0, 0, -240, 0, 0, + -240, 0, 0, -180, 0, 0, -120, 0, 0, -40, 0, 0, -20, 0, 0 + }, + { 20, 20, -20, -10, 0, -80, -40, 0, -140, -70, 0, -180, -90, 0, + -180, -90, 0, -180, -90, 0, -180, -90, 0, -180, -90, 0, + -180, -90, 0, -180, -90, 0, -180, -90, 0, -180, -90, 0, + -180, -90, 0, -180, -90, 0, -180, -90, 0, -180, -90, 0, + -180, -90, 0, -140, -70, 0, -80, -40, 0, -20, -10, 0 + }, + { 30, 30, 0, -10, 0, 0, -20, 0, 0, -60, 0, 0, -90, 0, 0, -120, 0, + 0, -120, 0, 0, -120, 0, 0, -120, 0, 0, -120, 0, 0, -120, 0, + 0, -120, 0, 0, -120, 0, 0, -120, 0, 0, -120, 0, 0, -120, 0, + 0, -120, 0, 0, -120, 0, 0, -120, 0, 0, -120, 0, 0, -120, 0, + 0, -120, 0, 0, -120, 0, 0, -120, 0, 0, -120, 0, 0, -120, 0, + 0, -120, 0, 0, -90, 0, 0, -60, 0, 0, -20, 0, 0, -10, 0 + }, + { 20, 20, +20, -10, 0, +80, -40, 0, +140, -70, 0, +180, -90, 0, + +180, -90, 0, +180, -90, 0, +180, -90, 0, +180, -90, 0, + +180, -90, 0, +180, -90, 0, +180, -90, 0, +180, -90, 0, + +180, -90, 0, +180, -90, 0, +180, -90, 0, +180, -90, 0, + +180, -90, 0, +140, -70, 0, +80, -40, 0, +20, -10, 0 + }, + { 30, 30, +20, 0, 0, +40, 0, 0, +120, 0, 0, +180, 0, 0, +240, 0, 0, + +240, 0, 0, +240, 0, 0, +240, 0, 0, +240, 0, 0, +240, 0, 0, + +240, 0, 0, +240, 0, 0, +240, 0, 0, +240, 0, 0, +240, 0, 0, + +240, 0, 0, +240, 0, 0, +240, 0, 0, +240, 0, 0, +240, 0, 0, + +240, 0, 0, +240, 0, 0, +240, 0, 0, +240, 0, 0, +240, 0, 0, + +240, 0, 0, +180, 0, 0, +120, 0, 0, +40, 0, 0, +20, 0, 0 + }, +#endif + }, + { 20, -1, -1, SOUND_R_ENGINE, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }, + }, + { + ACTION_R_APLAT, + CHBLUPI, + { + {1, 216}, // e + {1, 218}, // se + {1, 220}, // s + {1, 222}, // so + {1, 224}, // o + {1, 226}, // no + {1, 228}, // n + {1, 230}, // ne + }, + { + {40, 2, 0, 0, -2, 0, 0, +2}, + {40, 2, 0, 0, -2, 0, 0, +2}, + {40, 2, 0, 0, -2, 0, 0, +2}, + {40, 2, 0, 0, -2, 0, 0, +2}, + {40, 2, 0, 0, -2, 0, 0, +2}, + {40, 2, 0, 0, -2, 0, 0, +2}, + {40, 2, 0, 0, -2, 0, 0, +2}, + {40, 2, 0, 0, -2, 0, 0, +2}, + }, + { 30, -1, SOUND_R_APLAT, -1, -1, -1, SOUND_R_APLAT, -1, -1, + -1, SOUND_R_APLAT, -1, -1, -1, SOUND_R_APLAT, -1, -1, + -1, SOUND_R_APLAT, -1, -1, -1, SOUND_R_APLAT, -1, -1, + -1, SOUND_R_APLAT, -1, -1, -1, SOUND_R_APLAT + }, + }, + { + ACTION_R_BUILD, + CHBLUPI, + { + {8, 216, 231, 231, 216, 216, 217, 217, 216}, // e + {8, 218, 217, 217, 218, 218, 219, 219, 218}, // se + {8, 220, 219, 219, 220, 220, 221, 221, 220}, // s + {8, 222, 221, 221, 222, 222, 223, 223, 222}, // so + {8, 224, 223, 223, 224, 224, 225, 225, 224}, // o + {8, 226, 225, 225, 226, 226, 227, 227, 226}, // no + {8, 228, 227, 227, 228, 228, 229, 229, 228}, // n + {8, 230, 229, 229, 230, 230, 231, 231, 230}, // ne + }, + { + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + }, + { 30, -1, SOUND_R_ROTATE, -1, -1, -1, SOUND_R_ROTATE, -1, -1, + -1, SOUND_R_ROTATE, -1, -1, -1, SOUND_R_ROTATE, -1, -1, + -1, SOUND_R_ROTATE, -1, -1, -1, SOUND_R_ROTATE, -1, -1, + -1, SOUND_R_ROTATE, -1, -1, -1, SOUND_R_ROTATE + }, + }, + { + ACTION_R_DELAY, + CHBLUPI, + { + {1, 216}, // e + {1, 218}, // se + {1, 220}, // s + {1, 222}, // so + {1, 224}, // o + {1, 226}, // no + {1, 228}, // n + {1, 230}, // ne + }, + { + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + {40, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_R_LOAD, + CHBLUPI, + { + {1, 216}, // e + {1, 218}, // se + {1, 220}, // s + {1, 222}, // so + {1, 224}, // o + {1, 226}, // no + {1, 228}, // n + {1, 230}, // ne + }, + { + {40, 2, 0, 0, -1, 0, 0, +1}, + {40, 2, 0, 0, -1, 0, 0, +1}, + {40, 2, 0, 0, -1, 0, 0, +1}, + {40, 2, 0, 0, -1, 0, 0, +1}, + {40, 2, 0, 0, -1, 0, 0, +1}, + {40, 2, 0, 0, -1, 0, 0, +1}, + {40, 2, 0, 0, -1, 0, 0, +1}, + {40, 2, 0, 0, -1, 0, 0, +1}, + }, + {0}, + }, + { + ACTION_R_CRUSHED, + CHBLUPI, + { + {8, 216, 217, 217, 216, 216, 231, 231, 216}, // e + {8, 218, 219, 219, 218, 218, 217, 217, 218}, // se + {8, 220, 221, 221, 220, 220, 219, 219, 220}, // s + {8, 222, 223, 223, 222, 222, 221, 221, 222}, // so + {8, 224, 225, 225, 224, 224, 223, 223, 224}, // o + {8, 226, 227, 227, 226, 226, 225, 225, 226}, // no + {8, 228, 229, 229, 228, 228, 227, 227, 228}, // n + {8, 230, 231, 231, 230, 230, 229, 229, 230}, // ne + }, + { + {16, 1, 0, 0, 0}, + {16, 1, 0, 0, 0}, + {16, 1, 0, 0, 0}, + {16, 1, 0, 0, 0}, + {16, 1, 0, 0, 0}, + {16, 1, 0, 0, 0}, + {16, 1, 0, 0, 0}, + {16, 1, 0, 0, 0}, + }, + {0}, + }, + + // Bombe : + + { + ACTION_B_STOP, + CHBLUPI, + { + {1, 232}, // e + {1, 232}, // se + {1, 232}, // s + {1, 232}, // so + {1, 232}, // o + {1, 232}, // no + {1, 232}, // n + {1, 232}, // ne + }, + { + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_B_WALK, + CHBLUPI, + { + {10, 233, 233, 233, 233, 232, 232, 232, 232, 232, 232}, + {10, 233, 233, 233, 233, 232, 232, 232, 232, 232, 232}, + {10, 233, 233, 233, 233, 232, 232, 232, 232, 232, 232}, + {10, 233, 233, 233, 233, 232, 232, 232, 232, 232, 232}, + {10, 233, 233, 233, 233, 232, 232, 232, 232, 232, 232}, + {10, 233, 233, 233, 233, 232, 232, 232, 232, 232, 232}, + {10, 233, 233, 233, 233, 232, 232, 232, 232, 232, 232}, + {10, 233, 233, 233, 233, 232, 232, 232, 232, 232, 232}, + }, + { +#if 0 + { 20, 10, +150, +75, -4, +150, +75, -3, +150, +75, -2, +150, +75, -1, + +150, +75, 0, +150, +75, 0, + +150, +75, +1, +150, +75, +2, +150, +75, +3, +150, +75, +4 + }, + { 30, 10, 0, +100, -4, 0, +100, -3, 0, +100, -2, 0, +100, -1, + 0, +100, 0, 0, +100, 0, + 0, +100, +1, 0, +100, +2, 0, +100, +3, 0, +100, +4 + }, + { 20, 10, -150, +75, -4, -150, +75, -3, -150, +75, -2, -150, +75, -1, + -150, +75, 0, -150, +75, 0, + -150, +75, +1, -150, +75, +2, -150, +75, +3, -150, +75, +4 + }, + { 30, 10, -200, 0, -4, -200, 0, -3, -200, 0, -2, -200, 0, -1, + -200, 0, 0, -200, 0, 0, + -200, 0, +1, -200, 0, +2, -200, 0, +3, -200, 0, +4 + }, + { 20, 10, -150, -75, -4, -150, -75, -3, -150, -75, -2, -150, -75, -1, + -150, -75, 0, -150, -75, 0, + -150, -75, +1, -150, -75, +2, -150, -75, +3, -150, -75, +4 + }, + { 30, 10, 0, -100, -4, 0, -100, -3, 0, -100, -2, 0, -100, -1, + 0, -100, 0, 0, -100, 0, + 0, -100, +1, 0, -100, +2, 0, -100, +3, 0, -100, +4 + }, + { 20, 10, +150, -75, -4, +150, -75, -3, +150, -75, -2, +150, -75, -1, + +150, -75, 0, +150, -75, 0, + +150, -75, +1, +150, -75, +2, +150, -75, +3, +150, -75, +4 + }, + { 30, 10, +200, 0, -4, +200, 0, -3, +200, 0, -2, +200, 0, -1, + +200, 0, 0, +200, 0, 0, + +200, 0, +1, +200, 0, +2, +200, 0, +3, +200, 0, +4 + }, +#else + { 20, 10, 0, 0, +3, 0, 0, +4, 0, 0, -4, 0, 0, -3, +150, +75, -2, +300, +150, -1, + +300, +150, 0, +300, +150, 0, + +300, +150, +1, +150, +75, +2 + }, + { 30, 10, 0, 0, +3, 0, 0, +4, 0, 0, -4, 0, 0, -3, 0, +100, -2, 0, +200, -1, + 0, +200, 0, 0, +200, 0, + 0, +200, +1, 0, +100, +2 + }, + { 20, 10, 0, 0, +3, 0, 0, +4, 0, 0, -4, 0, 0, -3, -150, +75, -2, -300, +150, -1, + -300, +150, 0, -300, +150, 0, + -300, +150, +1, -150, +75, +2 + }, + { 30, 10, 0, 0, +3, 0, 0, +4, 0, 0, -4, 0, 0, -3, -200, 0, -2, -400, 0, -1, + -400, 0, 0, -400, 0, 0, + -400, 0, +1, -200, 0, +2 + }, + { 20, 10, 0, 0, +3, 0, 0, +4, 0, 0, -4, 0, 0, -3, -150, -75, -2, -300, -150, -1, + -300, -150, 0, -300, -150, 0, + -300, -150, +1, -150, -75, +2 + }, + { 30, 10, 0, 0, +3, 0, 0, +4, 0, 0, -4, 0, 0, -3, 0, -100, -2, 0, -200, -1, + 0, -200, 0, 0, -200, 0, + 0, -200, +1, 0, -100, +2 + }, + { 20, 10, 0, 0, +3, 0, 0, +4, 0, 0, -4, 0, 0, -3, +150, -75, -2, +300, -150, -1, + +300, -150, 0, +300, -150, 0, + +300, -150, +1, +150, -75, +2 + }, + { 30, 10, 0, 0, +3, 0, 0, +4, 0, 0, -4, 0, 0, -3, +200, 0, -2, +400, 0, -1, + +400, 0, 0, +400, 0, 0, + +400, 0, +1, +200, 0, +2 + }, +#endif + }, + { 30, -1, -1, SOUND_B_JUMP, -1, -1, -1, -1, -1, -1, -1, + -1, -1, SOUND_B_JUMP, -1, -1, -1, -1, -1, -1, -1, + -1, -1, SOUND_B_JUMP, -1, -1, -1, -1, -1, -1, -1 + }, + }, + + // Détonnateur de mine. + + { + ACTION_D_DELAY, + CHBLUPI, + { + {1, 0}, + {0} + }, + { + {15, 1, 0, 0, 0}, + }, + {0}, + }, + + // Electro : + + { + ACTION_E_STOP, + CHBLUPI, + { + {1, 266}, // e + {1, 266}, // se + {1, 266}, // s + {1, 266}, // so + {1, 266}, // o + {1, 266}, // no + {1, 266}, // n + {1, 266}, // ne + }, + { + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 1, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_E_WALK, + CHBLUPI, + { + {1, 266}, + {1, 266}, + {1, 266}, + {1, 266}, + {1, 266}, + {1, 266}, + {1, 266}, + {1, 266}, + }, + { + {5, 1, +600, +300, 0}, + {7, 1, 0, +429, 0}, + {5, 1, -600, +300, 0}, + {7, 1, -858, 0, 0}, + {5, 1, -600, -300, 0}, + {7, 1, 0, -429, 0}, + {5, 1, +600, -300, 0}, + {7, 1, +858, 0, 0}, + }, + {0}, + }, + { + ACTION_E_BEGIN, + CHBLUPI, + { + {1, 266}, + {1, 266}, + {1, 266}, + {1, 266}, + {1, 266}, + {1, 266}, + {1, 266}, + {1, 266}, + }, + { + {8, 8, 0, 0, -3, 0, 0, -2, 0, 0, -1, 0, 0, 0, 0, 0, +1, 0, 0, +2, 0, 0, +3, 0, 0, 0}, + {8, 8, 0, 0, -3, 0, 0, -2, 0, 0, -1, 0, 0, 0, 0, 0, +1, 0, 0, +2, 0, 0, +3, 0, 0, 0}, + {8, 8, 0, 0, -3, 0, 0, -2, 0, 0, -1, 0, 0, 0, 0, 0, +1, 0, 0, +2, 0, 0, +3, 0, 0, 0}, + {8, 8, 0, 0, -3, 0, 0, -2, 0, 0, -1, 0, 0, 0, 0, 0, +1, 0, 0, +2, 0, 0, +3, 0, 0, 0}, + {8, 8, 0, 0, -3, 0, 0, -2, 0, 0, -1, 0, 0, 0, 0, 0, +1, 0, 0, +2, 0, 0, +3, 0, 0, 0}, + {8, 8, 0, 0, -3, 0, 0, -2, 0, 0, -1, 0, 0, 0, 0, 0, +1, 0, 0, +2, 0, 0, +3, 0, 0, 0}, + {8, 8, 0, 0, -3, 0, 0, -2, 0, 0, -1, 0, 0, 0, 0, 0, +1, 0, 0, +2, 0, 0, +3, 0, 0, 0}, + {8, 8, 0, 0, -3, 0, 0, -2, 0, 0, -1, 0, 0, 0, 0, 0, +1, 0, 0, +2, 0, 0, +3, 0, 0, 0}, + }, + {0}, + }, + { + ACTION_E_RAYON, + CHBLUPI, + { + {4, 266, 267, 268, 269}, + {4, 266, 267, 268, 269}, + {4, 266, 267, 268, 269}, + {4, 266, 267, 268, 269}, + {4, 266, 267, 268, 269}, + {4, 266, 267, 268, 269}, + {4, 266, 267, 268, 269}, + {4, 266, 267, 268, 269}, + }, + { + {8, 1, 0, 0, 0}, + {8, 1, 0, 0, 0}, + {8, 1, 0, 0, 0}, + {8, 1, 0, 0, 0}, + {8, 1, 0, 0, 0}, + {8, 1, 0, 0, 0}, + {8, 1, 0, 0, 0}, + {8, 1, 0, 0, 0}, + }, + {0}, + }, + + { + -1 + } +}; +// clang-format on + +// Calcule l'action suivante. +// Retourne false lorsque l'action est terminée. + +bool +Action ( + Sint16 action, Sint16 direct, Sint16 & phase, Sint16 & step, Sint16 & channel, + Sint16 & icon, Point & pos, Sint16 & posZ, Sounds & sound) +{ + const auto * pTable = action_table; + Sint16 nbIcon, nbPhase, nbMove, nbSound, i; + + pos.x = 0; + pos.y = 0; + posZ = 0; + + while (pTable->action != -1) + { + if (action == pTable->action) + { + if (pTable->icons[1][0] == 0) + direct = 0; + + nbIcon = pTable->icons[direct / 16][0]; + nbPhase = pTable->moves[direct / 16][0]; + nbMove = pTable->moves[direct / 16][1]; + nbSound = pTable->sounds[0]; + + channel = pTable->channel; + icon = pTable->icons[direct / 16][1 + step % nbIcon]; + + if (nbSound == 0 || step >= nbSound) + sound = SOUND_NONE; + else + sound = + static_cast (pTable->sounds[1 + step % nbSound]); // FIXME + + for (i = 0; i < phase; i++) + { + pos.x += pTable->moves[direct / 16][2 + (i % nbMove) * 3 + 0]; + pos.y += pTable->moves[direct / 16][2 + (i % nbMove) * 3 + 1]; + posZ += pTable->moves[direct / 16][2 + (i % nbMove) * 3 + 2]; + } + + pos.x /= 100; + pos.y /= 100; + + if (phase >= nbPhase) + return false; + + phase++; + step++; + + return true; + } + + pTable++; + } + + return false; +} + +// clang-format off +static const Sint16 rotate_table[] = +{ + 0, 6, 12, 18, 24, 30, 36, 42, + 1, 7, 13, 19, 25, 31, 37, 43, + 2, 8, 14, 20, 26, 32, 38, 44, + 3, 9, 15, 21, 27, 33, 39, 45, + 4, 10, 16, 22, 28, 34, 40, 46, + 5, 11, 17, 23, 29, 35, 41, 47, + + 48, 49, 50, 51, 52, 53, 54, 55, + + 69, 72, 75, 78, 81, 84, 87, 90, + 70, 73, 76, 79, 82, 85, 88, 91, + 71, 74, 77, 80, 83, 86, 89, 92, + + 116, 118, 120, 122, 124, 126, 128, 130, + 117, 119, 121, 123, 125, 127, 129, 131, + + 322, 325, 328, 331, 334, 337, 340, 343, + 323, 326, 329, 332, 335, 338, 341, 344, + 324, 327, 330, 333, 336, 339, 342, 345, + + -1 +}; +// clang-format on + +// Tourne une icône dans une direction donnée. + +bool +Rotate (Sint16 & icon, Sint16 direct) +{ + const auto * pTable = rotate_table; + Sint16 i; + Sint16 offset = 0; + + if (icon >= 200 && icon <= 215) // tracks ? + { + icon = (direct / 8) + 200; + return true; + } + + if (icon >= 216 && icon <= 231) // robot ? + { + icon = (direct / 8) + 216; + return true; + } + + if (icon >= 290 && icon <= 305) // disciple ? + { + icon = (direct / 8) + 290; + return true; + } + + if (icon >= 234 && icon <= 249) // blupi en bateau ? + { + icon = (direct / 8) + 234; + return true; + } + + if (icon >= 250 && icon <= 265) // blupi en jeep ? + { + icon = (direct / 8) + 250; + return true; + } + + if (icon >= 169 && icon <= 192) // blupi malade ? + { + icon -= 100; + offset = 100; + } + + while (pTable[0] != -1) + { + for (i = 0; i < 8; i++) + { + if (icon == pTable[i]) + { + icon = pTable[direct / 16] + offset; + return true; + } + } + + pTable += 8; + } + + return false; +} + +// Retourne la direction d'une icône. + +Sint32 +GetIconDirect (Sint16 icon) +{ + const auto * pTable = rotate_table; + Sint16 i; + + if (icon >= 169 && icon <= 192) // blupi malade ? + icon -= 100; + + if (icon >= 234 && icon <= 249) // blupi en bateau ? + return ((icon - 234) / 2) * 16; + + if (icon >= 250 && icon <= 265) // blupi en jeep ? + return ((icon - 250) / 2) * 16; + + if (icon >= 290 && icon <= 305) // disciple ? + return ((icon - 290) / 2) * 16; + + while (pTable[0] != -1) + { + for (i = 0; i < 8; i++) + if (icon == pTable[i]) + return i * 16; + + pTable += 8; + } + + return -1; +} + +// Retourne l'amplitude d'une action, en nombre +// de cellules. + +Sint32 +GetAmplitude (Sint16 action) +{ + switch (action) + { + case ACTION_JUMP2: + return 2; + case ACTION_JUMP3: + return 3; + case ACTION_JUMP4: + return 4; + case ACTION_JUMP5: + return 5; + } + + return 1; +} diff --git a/src/action.h b/src/action.h new file mode 100644 index 0000000..81113f0 --- /dev/null +++ b/src/action.h @@ -0,0 +1,31 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include "blupi.h" +#include "def.h" + +extern bool Action ( + Sint16 action, Sint16 direct, Sint16 & phase, Sint16 & step, Sint16 & channel, + Sint16 & icon, Point & pos, Sint16 & posZ, Sounds & sound); +bool Rotate (Sint16 & icon, Sint16 direct); +Sint32 GetIconDirect (Sint16 icon); +Sint32 GetAmplitude (Sint16 action); diff --git a/src/blupi.cxx b/src/blupi.cxx new file mode 100644 index 0000000..e9fe1ec --- /dev/null +++ b/src/blupi.cxx @@ -0,0 +1,1158 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2019, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#ifdef USE_CURL +#include +#endif /* USE_CURL */ + +#include "json/json.hpp" + +#include "blupi.h" +#include "button.h" +#include "decor.h" +#include "def.h" +#include "event.h" +#include "menu.h" +#include "misc.h" +#include "movie.h" +#include "pixmap.h" +#include "platform.h" +#include "progress.h" +#include "sound.h" + +// Global variables + +SDL_Window * g_window; +SDL_Renderer * g_renderer; + +CEvent * g_pEvent = nullptr; +CPixmap * g_pPixmap = nullptr; // pixmap principal +CSound * g_pSound = nullptr; // sound principal +CMovie * g_pMovie = nullptr; // movie principal +CDecor * g_pDecor = nullptr; +std::thread * g_updateThread = nullptr; +std::atomic g_updateAbort (false); + +bool g_bFullScreen = false; // false si mode de test +Uint8 g_zoom = 1; +Sint32 g_speedRate = 1; +Sint32 g_timerInterval = 50; // inverval = 50ms +int g_rendererType = 0; +bool g_enableRecorder = false; +std::string g_playRecord; +bool g_restoreBugs = false; // restore original < v1.9 bugs +bool g_restoreMidi = false; // restore music playback based on midi files +bool g_renderQuality = true; // use the best render quality with scaling +int g_settingsOverload = 0; + +bool g_bTermInit = false; // initialisation en cours +Uint32 g_lastPhase = 999; +RestartMode g_restart = RestartMode::NO; +static bool g_pause; +static Uint32 g_prevPhase = 0; + +#ifdef USE_CURL +struct url_data { + CURLcode status; + char * buffer; + size_t size; +}; +#endif /* USE_CURL */ + +template +static void +split (const std::string & s, char delim, Out result) +{ + std::stringstream ss; + ss.str (s); + std::string item; + while (std::getline (ss, item, delim)) + *(result++) = item; +} + +static std::vector +split (const std::string & s, char delim) +{ + std::vector elems; + split (s, delim, std::back_inserter (elems)); + return elems; +} + +/** + * \brief Read the config file. + * + * \returns true on success. + */ +static bool +ReadConfig () +{ + const auto config = GetBaseDir () + "data/config.json"; + + std::ifstream file (config, std::ifstream::in); + if (!file) + return false; + + nlohmann::json j; + file >> j; + + if ( + !(g_settingsOverload & SETTING_SPEEDRATE) && + j.find ("speedrate") != j.end ()) + { + g_speedRate = j["speedrate"].get (); + if (g_speedRate < 1) + g_speedRate = 1; + if (g_speedRate > 2) + g_speedRate = 2; + } + + if ( + !(g_settingsOverload & SETTING_TIMERINTERVAL) && + j.find ("timerinterval") != j.end ()) + { + g_timerInterval = j["timerinterval"].get (); + if (g_timerInterval < 10) + g_timerInterval = 10; + if (g_timerInterval > 1000) + g_timerInterval = 1000; + } + + if ( + !(g_settingsOverload & SETTING_FULLSCREEN) && + j.find ("fullscreen") != j.end ()) + g_bFullScreen = j["fullscreen"].get (); + + if (!(g_settingsOverload & SETTING_ZOOM) && j.find ("zoom") != j.end ()) + { + g_zoom = j["zoom"].get (); + if (g_zoom != 1 && g_zoom != 2) + g_zoom = 1; + } + + if ( + !(g_settingsOverload & SETTING_RENDERER) && j.find ("renderer") != j.end ()) + { + if (j["renderer"] == "software") + g_rendererType = SDL_RENDERER_SOFTWARE; + else if (j["renderer"] == "accelerated") + g_rendererType = SDL_RENDERER_ACCELERATED; + } + + if ( + !(g_settingsOverload & SETTING_DRIVER) && j.find ("driver") != j.end () && + (!g_rendererType || g_rendererType == SDL_RENDERER_ACCELERATED)) + { + std::string input = j["driver"]; + if (std::regex_match ( + input, std::regex ("direct3d|direct3d11|opengl|opengles2|opengles"))) + SDL_SetHint (SDL_HINT_RENDER_DRIVER, input.c_str ()); + } + + if ( + !(g_settingsOverload & SETTING_MIDI) && j.find ("restoremidi") != j.end ()) + g_restoreMidi = j["restoremidi"].get (); + + if ( + !(g_settingsOverload & SETTING_RENDERQUALITY) && + j.find ("renderquality") != j.end ()) + g_renderQuality = j["renderquality"].get (); + + return true; +} + +/** + * \brief Main frame update. + */ +static bool +Update (void) +{ + Rect clip, rcRect; + Uint32 phase; + Point posMouse; + Sint32 i, term, speed; + bool display = true; + + posMouse = g_pEvent->GetLastMousePos (); + + phase = g_pEvent->GetPhase (); + + SDL_RenderClear (g_renderer); + + rcRect.left = 0; + rcRect.top = 0; + rcRect.right = LXIMAGE (); + rcRect.bottom = LYIMAGE (); + g_pPixmap->DrawImage (-1, CHBACK, rcRect); // draw the background + + if (phase == EV_PHASE_INTRO1) + g_pEvent->IntroStep (); + + if (phase == EV_PHASE_PLAY) + { + clip.left = POSDRAWX; + clip.top = POSDRAWY + g_pDecor->GetInfoHeight (); + clip.right = POSDRAWX + DIMDRAWX; + clip.bottom = POSDRAWY + DIMDRAWY; + + if (g_pEvent->IsShift ()) // screen shifting + g_pEvent->DecorAutoShift (); + + if (!g_pEvent->GetPause ()) + { + speed = g_pEvent->GetSpeed () * g_speedRate; + for (i = 0; i < speed; i++) + { + g_pDecor->BlupiStep (i == 0); // move all blupi + g_pDecor->MoveStep (i == 0); // move the environment + g_pEvent->DemoStep (); // forward the recording or demo playing + } + } + + g_pEvent->DecorAutoShift (); + g_pDecor->Build (clip, posMouse); // build the environment + g_pEvent->PlayMove (posMouse); + g_pDecor->NextPhase (1); // rebuild the map sometimes + } + + if (phase == EV_PHASE_BUILD) + { + clip.left = POSDRAWX; + clip.top = POSDRAWY; + clip.right = POSDRAWX + DIMDRAWX; + clip.bottom = POSDRAWY + DIMDRAWY; + g_pEvent->DecorAutoShift (); + g_pDecor->Build (clip, posMouse); // build the environment + g_pDecor->NextPhase (-1); // rebuild the map sometimes + } + + if (phase == EV_PHASE_INIT) + { + g_pEvent->DemoStep (); // start automatically (eventually) the demo + } + + SDL_Event event = {0}; + event.type = SDL_MOUSEMOTION; + event.motion.x = posMouse.x; + event.motion.y = posMouse.y; + g_pEvent->EventButtons (event, posMouse); + g_pEvent->MouseSprite (posMouse); + + g_pEvent->DrawButtons (); + + g_lastPhase = phase; + + if ( + phase == EV_PHASE_H0MOVIE || phase == EV_PHASE_H1MOVIE || + phase == EV_PHASE_H2MOVIE || phase == EV_PHASE_PLAYMOVIE || + phase == EV_PHASE_WINMOVIE) + { + display = g_pEvent->MovieToStart (); // start a movie if necessary + } + + if (phase == EV_PHASE_INSERT) + g_pEvent->TryInsert (); + + if (phase == EV_PHASE_PLAY) + { + term = g_pDecor->IsTerminated (); + if (term == 1) + g_pEvent->ChangePhase (EV_PHASE_LOST); // lost + if (term == 2) + g_pEvent->ChangePhase (EV_PHASE_WINMOVIE); // win + } + + if (g_prevPhase != phase) + { + Point pos; + + pos.x = LXIMAGE () / 2; + pos.y = LYIMAGE () / 2; + + if (phase == EV_PHASE_LOST) + { + if (!g_pSound->PlayImage (SOUND_LOST, pos)) + g_pSound->PlayImage (SOUND_GOAL, pos); + } + else if (phase == EV_PHASE_WIN || phase == EV_PHASE_LASTWIN) + { + if (!g_pSound->PlayImage (SOUND_WIN, pos)) + g_pSound->PlayImage (SOUND_GOAL, pos); + } + } + + g_prevPhase = phase; + + return display; +} + +/** + * \brief Finished with all objects we use; release them. + */ +static void +FinishObjects (void) +{ + if (g_pMovie != nullptr) + { + delete g_pMovie; + g_pMovie = nullptr; + } + + if (g_pEvent != nullptr) + { + delete g_pEvent; + g_pEvent = nullptr; + } + + if (g_pDecor != nullptr) + { + delete g_pDecor; + g_pDecor = nullptr; + } + + if (g_pSound != nullptr) + { + g_pSound->StopMusic (); + + delete g_pSound; + g_pSound = nullptr; + } + + if (g_pPixmap != nullptr) + { + delete g_pPixmap; + g_pPixmap = nullptr; + } +} + +static void +HandleEvent (const SDL_Event & event) +{ + if (!g_pause && g_pEvent != nullptr && g_pEvent->TreatEvent (event)) + return; + + switch (event.type) + { + case SDL_WINDOWEVENT: + { +#ifndef DEBUG + Point totalDim, iconDim; + + switch (event.window.event) + { + case SDL_WINDOWEVENT_FOCUS_GAINED: + g_pause = false; + + if (g_bFullScreen) + g_lastPhase = 999; + + if (!g_bFullScreen && g_bTermInit) + { + totalDim.x = 64; + totalDim.y = 66; + iconDim.x = 64; + iconDim.y = 66 / 2; + g_pPixmap->Cache (CHHILI, "hili.png", totalDim, iconDim); + } + SDL_SetWindowTitle (g_window, gettext ("Planet Blupi")); + if (g_pSound != nullptr) + g_pSound->RestartMusic (); + if (g_pMovie) + g_pMovie->Resume (); + return; + + case SDL_WINDOWEVENT_FOCUS_LOST: + g_pause = true; + + SDL_SetWindowTitle (g_window, gettext ("Planet Blupi -- stop")); + if (g_pSound != nullptr) + g_pSound->SuspendMusic (); + if (g_pMovie) + g_pMovie->Pause (); + return; + } +#endif /* !DEBUG */ + break; + } + + case SDL_KEYDOWN: + switch (event.key.keysym.sym) + { + case SDLK_F5: + g_pEvent->SetSpeed (1); + break; + case SDLK_F6: + g_pEvent->SetSpeed (2); + break; + case SDLK_F7: + g_pEvent->SetSpeed (4); + break; + case SDLK_F8: + g_pEvent->SetSpeed (8); + break; + } + break; + + case SDL_RENDER_DEVICE_RESET: + case SDL_RENDER_TARGETS_RESET: + g_pDecor->InvalidateGrounds (); + g_pPixmap->ReloadTargetTextures (); + g_pEvent->LoadBackground (); + break; + + case SDL_USEREVENT: + { + switch (event.user.code) + { + case EV_UPDATE: + if (!g_pEvent->IsMovie ()) // pas de film en cours ? + { + bool display = true; + + if (!g_pause) + display = Update (); + + if (!g_pEvent->IsMovie () && display) + g_pPixmap->Display (); + } + break; + + case EV_WARPMOUSE: + { + const SDL_Point * coord = static_cast (event.user.data1); + + Sint32 x = coord->x, y = coord->y; + g_pPixmap->FromGameToDisplay (x, y); + SDL_WarpMouseInWindow (g_window, x, y); + delete coord; + break; + } + + case EV_CHECKUPDATE: + { + std::string * data = static_cast (event.user.data1); + + using json = nlohmann::json; + json jsonData = json::parse (*data); + + /* Check if the remote version is newer */ + std::vector list = split (jsonData["version"], '.'); + std::vector version (3); + std::transform ( + list.begin (), list.end (), version.begin (), + [](const std::string & s) -> unsigned int { return std::stoi (s); }); + + if ( + (!!PB_VERSION_EXTRA[0] && + PB_VERSION_INT (version[0], version[1], version[2]) >= + PLANETBLUPI_VERSION_INT) || + PB_VERSION_INT (version[0], version[1], version[2]) > + PLANETBLUPI_VERSION_INT) + g_pEvent->SetUpdateVersion (jsonData["version"]); + + delete data; + } + + case EV_MUSIC_STOP: + if (g_pSound->IsStoppedOnDemand ()) + break; + + g_pSound->RestartMusic (); + break; + + case EV_MOVIE_PLAY: + if (!g_pMovie->Render ()) + g_pEvent->StopMovie (); + break; + } + break; + } + } +} + +// Error with DoInit function. + +static void +InitFail (const char * msg) +{ + char buffer[100]; + + strcpy (buffer, "Error ("); + strcat (buffer, msg); + strcat (buffer, ")"); + + SDL_ShowSimpleMessageBox ( + SDL_MessageBoxFlags::SDL_MESSAGEBOX_ERROR, "Error", buffer, g_window); + + FinishObjects (); +} + +#ifdef USE_CURL +static size_t +updateCallback (void * ptr, size_t size, size_t nmemb, void * data) +{ + size_t realsize = size * nmemb; + url_data * mem = static_cast (data); + + mem->buffer = + static_cast (realloc (mem->buffer, mem->size + realsize + 1)); + if (mem->buffer) + { + memcpy (&(mem->buffer[mem->size]), ptr, realsize); + mem->size += realsize; + mem->buffer[mem->size] = 0; + } + + return realsize; +} + +static int +progressCallback ( + void * userData, double dltotal, double dlnow, double ultotal, double ulnow) +{ + return g_updateAbort ? 1 : 0; +} +#endif /* USE_CURL */ + +#ifdef USE_CURL +static void +CheckForUpdates () +{ + url_data chunk; + + chunk.buffer = nullptr; /* we expect realloc(NULL, size) to work */ + chunk.size = 0; /* no data at this point */ + chunk.status = CURLE_FAILED_INIT; + + CURL * curl = curl_easy_init (); + if (!curl) + return; + + curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt (curl, CURLOPT_FAILONERROR, 1); + curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt (curl, CURLOPT_TIMEOUT, 20); + curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, 5); + + curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, updateCallback); + + curl_easy_setopt (curl, CURLOPT_URL, "http://blupi.org/update/planet.json"); + curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *) &chunk); + + curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 0); + curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, nullptr); + curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, progressCallback); + + chunk.status = curl_easy_perform (curl); + + if (chunk.status) + { + const char * err = curl_easy_strerror (chunk.status); + SDL_LogError ( + SDL_LOG_CATEGORY_APPLICATION, "Check for updates, error: %s", err); + } + else + { + std::string * res = new std::string (chunk.buffer, chunk.size); + CEvent::PushUserEvent (EV_CHECKUPDATE, res); + } + + if (chunk.buffer) + free (chunk.buffer); + + curl_easy_cleanup (curl); +} +#endif /* USE_CURL */ + +static int +parseArgs (int argc, char * argv[], bool & exit) +{ + argagg::parser argparser{ + {{"help", {"-h", "--help"}, "print this help message and exit", 0}, + {"version", {"-V", "--version"}, "print version and exit", 0}, + {"speedrate", + {"-s", "--speed-rate"}, + "change the speed rate [1;2] (default: 1)", + 1}, + {"timerinterval", + {"-t", "--timer-interval"}, + "set the timer interval (refresh)", + 1}, + {"fullscreen", + {"-f", "--fullscreen"}, + "load in fullscreen [on;off] (default: on)", + 1}, + {"zoom", + {"-z", "--zoom"}, + "change the window scale (only if fullscreen is off) [1;2] (default: 1)", + 1}, + {"legacy", + {"-l", "--legacy"}, + "start the game in legacy display mode (640x480)", + 0}, + {"renderer", + {"-r", "--renderer"}, + "set a renderer [auto;software;accelerated] (default: auto)", + 1}, + {"driver", + {"-d", "--driver"}, + "set a driver [auto;direct3d;direct3d11;opengl;opengles2;opengles] " + "(default: auto, ignored with " + "software renderer)", + 1}, + {"enablerecorder", + {"-c", "--enable-recorder"}, + "enable the recorder feature (F3/F4)", + 0}, + {"playrecord", + {"-p", "--play-record"}, + "play a record generated by F3 (--enable-recorder)", + 1}, + {"restorebugs", + {"-b", "--restore-bugs"}, + "restore funny original bugs of older versions < v1.9", + 0}, + {"restoremidi", + {"-m", "--restore-midi"}, + "restore playback based on MIDI music instead of OGG", + 0}, + {"renderquality", + {"-q", "--render-quality"}, + "enable anti-aliasing [on;off] (default: on, ignored if " + "windowed)", + 1}}}; + + argagg::parser_results args; + try + { + args = argparser.parse (argc, argv); + } + catch (const std::exception & e) + { + std::cerr << e.what () << std::endl; + exit = true; + return EXIT_FAILURE; + } + + if (args["help"]) + { + std::cerr << "Usage: planetblupi [options]" << std::endl << argparser; + exit = true; + return EXIT_SUCCESS; + } + + if (args["version"]) + { + std::cerr << PLANETBLUPI_VERSION_STR << std::endl; + exit = true; + return EXIT_SUCCESS; + } + + if (args["speedrate"]) + { + g_speedRate = args["speedrate"]; + g_settingsOverload |= SETTING_SPEEDRATE; + } + + if (args["timerinterval"]) + { + g_timerInterval = args["timerinterval"]; + g_settingsOverload |= SETTING_TIMERINTERVAL; + } + + if (args["fullscreen"]) + { + g_bFullScreen = + args["fullscreen"].as () != std::string ("off"); + g_settingsOverload |= SETTING_FULLSCREEN; + } + + if (args["zoom"]) + { + g_zoom = args["zoom"]; + if (g_zoom != 1 && g_zoom != 2) + g_zoom = 1; + g_settingsOverload |= SETTING_ZOOM; + } + + if (args["legacy"]) + { + Display::getDisplay ().setDisplaySize (LXLOGIC (), LYLOGIC ()); + g_settingsOverload |= SETTING_LEGACY; + } + + if (args["renderer"]) + { + if (args["renderer"].as () == "auto") + g_rendererType = 0; + else if (args["renderer"].as () == "software") + g_rendererType = SDL_RENDERER_SOFTWARE; + else if (args["renderer"].as () == "accelerated") + g_rendererType = SDL_RENDERER_ACCELERATED; + g_settingsOverload |= SETTING_RENDERER; + } + + if ( + args["driver"] && + (!g_rendererType || g_rendererType == SDL_RENDERER_ACCELERATED)) + { + std::string input = args["driver"].as (); + if (std::regex_match ( + input, std::regex ("direct3d|direct3d11|opengl|opengles2|opengles"))) + SDL_SetHint (SDL_HINT_RENDER_DRIVER, input.c_str ()); + g_settingsOverload |= SETTING_DRIVER; + } + + if (args["enablerecorder"]) + g_enableRecorder = true; + + if (args["playrecord"]) + g_playRecord = args["playrecord"].as (); + + if (args["restorebugs"]) + g_restoreBugs = true; + + if (args["restoremidi"]) + { + g_restoreMidi = true; + g_settingsOverload |= SETTING_MIDI; + } + + if (args["renderquality"]) + { + g_renderQuality = + args["renderquality"].as () != std::string ("off"); + g_settingsOverload |= SETTING_RENDERQUALITY; + } + + return EXIT_SUCCESS; +} + +// Main initialization function. + +static int +DoInit (int argc, char * argv[], bool & exit) +{ + int rc = parseArgs (argc, argv, exit); + if (exit) + return rc; + + Point totalDim, iconDim; + Rect rcRect; + bool bOK; + + bOK = ReadConfig (); // lit le fichier config.json + + if (!bOK) // Something wrong with config.json file? + { + InitFail ("Game not correctly installed"); + return EXIT_FAILURE; + } + +#ifdef __LINUX__ + if (!getenv ("ALSA_CONFIG_DIR")) + { + static char env[256]; + snprintf (env, sizeof (env), "ALSA_CONFIG_DIR=/usr/share/alsa"); + putenv (env); + } +#endif /* __LINUX__ */ + +#ifdef _WIN32 + /* Fix laggy sounds on Windows by not using winmm driver. */ + SDL_setenv ("SDL_AUDIODRIVER", "directsound", true); +#endif /* _WIN32 */ + + auto res = SDL_Init (SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER); + if (res < 0) + { + SDL_Log ("Unable to initialize SDL: %s", SDL_GetError ()); + return EXIT_FAILURE; + } + + if (!(g_settingsOverload & SETTING_LEGACY)) + Display::getDisplay ().readDisplaySize (); + + // Create a window. + g_window = SDL_CreateWindow ( + gettext ("Planet Blupi"), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + LXIMAGE (), LYIMAGE (), 0); + + if (!g_window) + { + printf ("%s", SDL_GetError ()); + return EXIT_FAILURE; + } + +#if 0 + auto icon = IMG_Load ((GetShareDir () + "icons/hicolor/256x256/apps/blupi.png").c_str ()); + SDL_SetWindowIcon (g_window, icon); + SDL_FreeSurface (icon); +#endif /* 0 */ + + g_renderer = SDL_CreateRenderer ( + g_window, -1, g_rendererType | SDL_RENDERER_TARGETTEXTURE); + if (!g_renderer) + { + printf ("%s", SDL_GetError ()); + SDL_DestroyWindow (g_window); + return EXIT_FAILURE; + } + + SDL_RenderSetLogicalSize (g_renderer, LXIMAGE (), LYIMAGE ()); + + const auto renders = SDL_GetNumRenderDrivers (); + for (int i = 0; i < renders; ++i) + { + SDL_RendererInfo info = {0}; + if (SDL_GetRenderDriverInfo (i, &info)) + { + SDL_LogError (SDL_LOG_CATEGORY_APPLICATION, "renderer[%d]: failed\n", i); + continue; + } + + SDL_LogInfo ( + SDL_LOG_CATEGORY_APPLICATION, "renderer[%d]: name=%s", i, info.name); + SDL_LogInfo ( + SDL_LOG_CATEGORY_APPLICATION, "renderer[%d]: flags=%u", i, info.flags); + SDL_LogInfo ( + SDL_LOG_CATEGORY_APPLICATION, "renderer[%d]: num_texture_formats=%u", i, + info.num_texture_formats); + SDL_LogInfo ( + SDL_LOG_CATEGORY_APPLICATION, "renderer[%d]: max_texture_width=%u", i, + info.max_texture_width); + SDL_LogInfo ( + SDL_LOG_CATEGORY_APPLICATION, "renderer[%d]: max_texture_height=%u", i, + info.max_texture_height); + } + + // Create the event manager. + g_pEvent = new CEvent; + if (g_pEvent == nullptr) + { + InitFail ("New event"); + return EXIT_FAILURE; + } + + // Create the main pixmap. + g_pPixmap = new CPixmap (g_pEvent); + if (g_pPixmap == nullptr) + { + InitFail ("New pixmap"); + return EXIT_FAILURE; + } + + totalDim.x = LXIMAGE (); + totalDim.y = LYIMAGE (); + if (!g_pPixmap->Create (totalDim)) + { + InitFail ("Create pixmap"); + return EXIT_FAILURE; + } + + OutputDebug ("Image: init\n"); + totalDim.x = LXLOGIC (); + totalDim.y = LYLOGIC (); + iconDim.x = 0; + iconDim.y = 0; +#if _INTRO + if (!g_pPixmap->Cache (CHBACK, "intro1.png", totalDim, iconDim)) +#else + if (!g_pPixmap->Cache (CHBACK, "init.png", totalDim, iconDim)) +#endif + return EXIT_FAILURE; + + OutputDebug ("Image: init\n"); + totalDim.x = LXIMAGE (); + totalDim.y = LYIMAGE (); + if (!g_pPixmap->Cache (CHGROUND, totalDim)) + return EXIT_FAILURE; + + rcRect.left = 0; + rcRect.top = 0; + rcRect.right = LXIMAGE (); + rcRect.bottom = LYIMAGE (); + g_pPixmap->DrawImage (-1, CHBACK, rcRect); // dessine le fond + g_pPixmap->Display (); + + totalDim.x = DIMCELX * 2 * 16; + totalDim.y = DIMCELY * 2 * 6; + iconDim.x = DIMCELX * 2; + iconDim.y = DIMCELY * 2; + if (!g_pPixmap->Cache (CHFLOOR, "floor000.png", totalDim, iconDim)) + { + InitFail ("Cache floor000.png"); + return EXIT_FAILURE; + } + + totalDim.x = DIMOBJX * 16; + totalDim.y = DIMOBJY * 8; + iconDim.x = DIMOBJX; + iconDim.y = DIMOBJY; + if (!g_pPixmap->Cache (CHOBJECT, "obj000.png", totalDim, iconDim)) + { + InitFail ("Cache obj000.png"); + return EXIT_FAILURE; + } + + if (!g_pPixmap->Cache (CHOBJECTo, "obj-o000.png", totalDim, iconDim)) + { + InitFail ("Cache obj-o000.png"); + return EXIT_FAILURE; + } + + totalDim.x = DIMBLUPIX * 16; + totalDim.y = DIMBLUPIY * 23; + iconDim.x = DIMBLUPIX; + iconDim.y = DIMBLUPIY; + if (!g_pPixmap->Cache (CHBLUPI, "blupi.png", totalDim, iconDim)) + { + InitFail ("Cache blupi.png"); + return EXIT_FAILURE; + } + + totalDim.x = 64; + totalDim.y = 66; + iconDim.x = 64; + iconDim.y = 66 / 2; + if (!g_pPixmap->Cache (CHHILI, "hili.png", totalDim, iconDim)) + { + InitFail ("Cache hili.png"); + return EXIT_FAILURE; + } + + totalDim.x = DIMCELX * 2 * 3; + totalDim.y = DIMCELY * 2 * 5; + iconDim.x = DIMCELX * 2; + iconDim.y = DIMCELY * 2; + if (!g_pPixmap->Cache (CHFOG, "fog.png", totalDim, iconDim)) + { + InitFail ("Cache fog.png"); + return EXIT_FAILURE; + } + + totalDim.x = DIMCELX * 2 * 16; + totalDim.y = DIMCELY * 2 * 1; + iconDim.x = DIMCELX * 2; + iconDim.y = DIMCELY * 2; + if (!g_pPixmap->Cache (CHMASK1, "mask1.png", totalDim, iconDim)) + { + InitFail ("Cache mask1.png"); + return EXIT_FAILURE; + } + + totalDim.x = DIMCELX * 2 * 16; + totalDim.y = DIMCELY * 2 * 1; + iconDim.x = DIMCELX * 2; + iconDim.y = DIMCELY * 2; + if (!g_pPixmap->Cache (CHMASK2, "mask2.png", totalDim, iconDim)) + { + InitFail ("Cache mask2.png"); + return EXIT_FAILURE; + } + + totalDim.x = DIMBUTTONX * 6; + totalDim.y = DIMBUTTONY * 21; + iconDim.x = DIMBUTTONX; + iconDim.y = DIMBUTTONY; + if (!g_pPixmap->Cache (CHBUTTON, "button00.png", totalDim, iconDim)) + { + InitFail ("Cache button00.png"); + return EXIT_FAILURE; + } + + totalDim.x = DIMJAUGEX * 1; + totalDim.y = DIMJAUGEY * 4; + iconDim.x = DIMJAUGEX; + iconDim.y = DIMJAUGEY; + if (!g_pPixmap->Cache (CHJAUGE, "jauge.png", totalDim, iconDim)) + { + InitFail ("Cache jauge.png"); + return EXIT_FAILURE; + } + + totalDim.x = DIMTEXTX * 16; + totalDim.y = DIMTEXTY * 16 * 3; + iconDim.x = DIMTEXTX; + iconDim.y = DIMTEXTY; + if (!g_pPixmap->Cache (CHTEXT, "text.png", totalDim, iconDim)) + { + InitFail ("Cache text.png"); + return EXIT_FAILURE; + } + + totalDim.x = DIMLITTLEX * 16; + totalDim.y = DIMLITTLEY * 16; + iconDim.x = DIMLITTLEX; + iconDim.y = DIMLITTLEY; + if (!g_pPixmap->Cache (CHLITTLE, "little.png", totalDim, iconDim)) + { + InitFail ("Cache little.png"); + return EXIT_FAILURE; + } + + totalDim.x = 426; + totalDim.y = 52; + iconDim.x = 426; + iconDim.y = 52; + if (!g_pPixmap->Cache (CHBIGNUM, "bignum.png", totalDim, iconDim)) + { + InitFail ("Cache bignum.png"); + return EXIT_FAILURE; + } + + // Create the sound manager. + g_pSound = new CSound; + if (g_pSound == nullptr) + { + InitFail ("New sound"); + return EXIT_FAILURE; + } + + g_pSound->Create (); + g_pSound->CacheAll (); + g_pSound->SetState (true); + + // Create the movie manager. + g_pMovie = new CMovie (g_pPixmap); + if (g_pMovie == nullptr) + { + InitFail ("New movie"); + return EXIT_FAILURE; + } + + g_pMovie->Create (); + + // Create the decor manager. + g_pDecor = new CDecor; + if (g_pDecor == nullptr) + { + InitFail ("New decor"); + return EXIT_FAILURE; + } + + g_pDecor->Create (g_pSound, g_pPixmap); + g_pDecor->MapInitColors (); + + const bool zoom = g_zoom; + + const bool renderQuality = g_renderQuality; + g_pEvent->Create (g_pPixmap, g_pDecor, g_pSound, g_pMovie); + if (renderQuality != g_renderQuality) + g_pPixmap->CreateMainTexture (); + + // Load all cursors + g_pPixmap->LoadCursors (); + g_pPixmap->ChangeSprite (SPRITE_WAIT); + +#ifdef USE_CURL + g_updateThread = new std::thread (CheckForUpdates); +#endif /* USE_CURL */ + + if (zoom != g_zoom) + g_pEvent->SetWindowSize (g_zoom); + g_pEvent->SetFullScreen (g_bFullScreen); + g_pEvent->ChangePhase (EV_PHASE_INTRO1); + + g_bTermInit = true; + return EXIT_SUCCESS; +} + +static void +initGettext () +{ + setlocale (LC_ALL, ""); + textdomain ("planetblupi"); + bindtextdomain ("planetblupi", (GetShareDir () + "locale").c_str ()); + bind_textdomain_codeset ("planetblupi", "UTF-8"); +} + +int +main (int argc, char * argv[]) +{ + initGettext (); + + int res = 0; + bool exit = false; + if ((res = DoInit (argc, argv, exit)) || exit) + return res; + + Platform::run (HandleEvent); + + FinishObjects (); + + if (g_renderer) + SDL_DestroyRenderer (g_renderer); + + if (g_window) + SDL_DestroyWindow (g_window); + + SDL_Quit (); + + if (g_updateThread) + { + g_updateAbort = true; + g_updateThread->join (); + delete (g_updateThread); + } + + /* Restart the game when the fullscreen mode (ratio) has changed. */ + if (g_restart != RestartMode::NO) + { + std::vector _argv; + std::string argv0; + std::string bin = basename (argv[0]); + + if (getenv ("APPIMAGE")) + argv0 = getenv ("APPIMAGE"); + else + argv0 = GetBinDir () + bin; + + _argv.push_back (bin.c_str ()); + if (g_restart == RestartMode::LEGACY) + { + _argv.push_back ("--legacy"); + _argv.push_back ("--fullscreen"); + _argv.push_back ("on"); + _argv.push_back ("--zoom"); + _argv.push_back ("2"); + } + _argv.push_back (nullptr); + + SDL_Log ("Reload the game from %s", argv0.c_str ()); + execv (argv0.c_str (), const_cast (&_argv[0])); + } + + return 0; +} diff --git a/src/blupi.h b/src/blupi.h new file mode 100644 index 0000000..6b781cc --- /dev/null +++ b/src/blupi.h @@ -0,0 +1,118 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include +#include +#include + +#include "config.h" + +class CEvent; + +enum RestartMode { NO = 0, LEGACY, DESKTOP }; + +extern SDL_Window * g_window; +extern SDL_Renderer * g_renderer; +extern bool g_bFullScreen; +extern Uint8 g_zoom; +extern bool g_restoreBugs; +extern bool g_restoreMidi; +extern bool g_renderQuality; +extern bool g_enableRecorder; +extern std::string g_playRecord; +extern CEvent * g_pEvent; +extern RestartMode g_restart; +extern Sint32 g_timerInterval; + +enum Settings { + SETTING_FULLSCREEN = 1 << 0, + SETTING_SPEEDRATE = 1 << 1, + SETTING_TIMERINTERVAL = 1 << 2, + SETTING_RENDERER = 1 << 3, + SETTING_ZOOM = 1 << 4, + SETTING_DRIVER = 1 << 5, + SETTING_MIDI = 1 << 6, + SETTING_LEGACY = 1 << 7, + SETTING_RENDERQUALITY = 1 << 8, +}; + +extern int g_settingsOverload; + +struct Point { + Sint32 x; + Sint32 y; +}; + +struct Rect { + Sint32 left; + Sint32 top; + Sint32 right; + Sint32 bottom; +}; + +typedef Uint32 ColorRef; + +#if defined(_WIN64) +typedef unsigned __int64 WParam; +typedef __int64 LParam; +#else +typedef Uint32 WParam; +typedef Sint32 LParam; +#endif + +#undef LOWORD +#undef HIWORD +#define LOWORD(l) ((Uint16) (((Uint32) (l)) & 0xffff)) +#define HIWORD(l) ((Uint16) ((((Uint32) (l)) >> 16) & 0xffff)) + +#define PB_STRINGIFY(s) #s +#define PB_TOSTRING(s) PB_STRINGIFY (s) +#define PB_VERSION_INT(a, b, c) (a << 16 | b << 8 | c) +#define PB_VERSION_DOT(a, b, c) a##.##b##.##c +#define PB_VERSION(a, b, c) PB_VERSION_DOT (a, b, c) +#define PLANETBLUPI_VERSION \ + PB_VERSION (PB_VERSION_MAJOR, PB_VERSION_MINOR, PB_VERSION_PATCH) +#define PLANETBLUPI_VERSION_INT \ + PB_VERSION_INT (PB_VERSION_MAJOR, PB_VERSION_MINOR, PB_VERSION_PATCH) +#define PLANETBLUPI_VERSION_STR PB_TOSTRING (PLANETBLUPI_VERSION) + +#ifdef _WIN32 +#define countof(a) _countof (a) +#else /* _WIN32 */ +#define countof(a) (sizeof (a) / sizeof (*a)) +#endif /* !_WIN32 */ + +// clang-format off +#define VK_END 0x23 +#define VK_LEFT 0x25 +#define VK_UP 0x26 +#define VK_RIGHT 0x27 +#define VK_DOWN 0x28 + +#define EV_KEYDOWN 0x0100 +#define EV_KEYUP 0x0101 +#define EV_MOUSEMOVE 0x0200 +#define EV_LBUTTONDOWN 0x0201 +#define EV_LBUTTONUP 0x0202 +#define EV_RBUTTONDOWN 0x0204 +#define EV_RBUTTONUP 0x0205 +// clang-format on diff --git a/src/button.cxx b/src/button.cxx new file mode 100644 index 0000000..fe934ed --- /dev/null +++ b/src/button.cxx @@ -0,0 +1,453 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2019, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include +#include + +#include "button.h" +#include "decor.h" +#include "def.h" +#include "event.h" +#include "gettext.h" +#include "misc.h" +#include "pixmap.h" +#include "sound.h" + +CButton::CButton () +{ + m_type = 0; + m_bEnable = true; + m_bHide = false; + m_state = 0; + m_mouseState = 0; + m_nbMenu = 0; + m_nbToolTips = 0; + m_selMenu = 0; + m_bMouseDown = false; + m_message = static_cast (-1); + m_pPixmap = nullptr; + m_pDecor = nullptr; + m_pSound = nullptr; + m_toolTips = nullptr; +} + +CButton::~CButton () {} + +// Crée un nouveau bouton. + +bool +CButton::Create ( + CPixmap * pPixmap, CSound * pSound, Point pos, Sint32 type, Sint32 * pMenu, + Sint32 nbMenu, const char ** pToolTips, Sint32 region, Uint32 message, + bool isRightReading) +{ + Point iconDim; + Sint32 i, icon; + + static Sint32 ttypes[] = { + DIMBUTTONX, DIMBUTTONY, // button00.bmp + }; + + if (type < 0 || type > 0) + return false; + + iconDim.x = ttypes[type * 2 + 0]; + iconDim.y = ttypes[type * 2 + 1]; + + m_pPixmap = pPixmap; + m_pSound = pSound; + m_type = type; + m_bEnable = true; + m_bHide = false; + m_message = message; + m_pos = pos; + m_dim = iconDim; + m_nbMenu = nbMenu; + m_selMenu = 0; + m_state = 0; + m_mouseState = 0; + m_bMouseDown = false; + + m_nbToolTips = 0; + while (pToolTips[m_nbToolTips]) + ++m_nbToolTips; + + for (i = 0; i < nbMenu; i++) + { + icon = pMenu[i]; + + if (isRightReading) + { + if (icon == 51) // right arrow + icon = 50; + else if (icon == 50) // left arrow + icon = 51; + else if (icon == 40) // stop + icon = 109; + } + + if (region == 1) // palmiers ? + { + if (icon == 0) + icon = 90; // sol normal + if (icon == 1) + icon = 91; // sol inflammable + if (icon == 2) + icon = 92; // sol inculte + if (icon == 7) + icon = 9; // plante + if (icon == 8) + icon = 10; // arbre + } + + if (region == 2) // hiver ? + { + if (icon == 0) + icon = 96; // sol normal + if (icon == 1) + icon = 97; // sol inflammable + if (icon == 2) + icon = 98; // sol inculte + if (icon == 8) + icon = 99; // arbre + } + + if (region == 3) // sapin ? + { + if (icon == 0) + icon = 102; // sol normal + if (icon == 1) + icon = 103; // sol inflammable + if (icon == 2) + icon = 104; // sol inculte + if (icon == 8) + icon = 105; // arbre + } + + m_iconMenu[i] = icon; + } + + m_toolTips = pToolTips; + + return true; +} + +// Dessine un bouton dans son état. + +void +CButton::Draw () +{ + Sint32 i; + Point pos = this->m_pos; + Rect rect; + + if (m_bHide) // bouton caché ? + { + rect.left = pos.x; + rect.right = pos.x + m_dim.x; + rect.top = pos.y; + rect.bottom = pos.y + m_dim.y; + m_pPixmap->DrawPart (-1, CHBACK, pos, rect); // dessine le fond + return; + } + + if (m_bEnable) // bouton actif ? + m_pPixmap->DrawIcon (-1, CHBUTTON + m_type, m_mouseState, pos); + else + m_pPixmap->DrawIcon (-1, CHBUTTON + m_type, 4, pos); + + if (m_nbMenu == 0) + return; + + if (m_nbMenu > 0) + { + m_pPixmap->DrawIcon (-1, CHBUTTON + m_type, m_iconMenu[m_selMenu] + 6, pos); + } + + if (m_nbMenu == 1 || !m_bEnable || !m_bMouseDown) + return; + + pos.x += IsRightReading () ? -m_dim.x - 2 : m_dim.x + 2; + for (i = 0; i < m_nbMenu; i++) + { + m_pPixmap->DrawIcon (-1, CHBUTTON + m_type, i == m_selMenu ? 1 : 0, pos); + m_pPixmap->DrawIcon (-1, CHBUTTON + m_type, m_iconMenu[i] + 6, pos); + pos.x += IsRightReading () ? -m_dim.x - 1 : m_dim.x - 1; + } +} + +Sint32 +CButton::GetState () +{ + return m_state; +} + +void +CButton::SetState (Sint32 state) +{ + m_state = state; + m_mouseState = state; +} + +Sint32 +CButton::GetMenu () +{ + return m_selMenu; +} + +void +CButton::SetMenu (Sint32 menu) +{ + m_selMenu = menu; +} + +bool +CButton::GetEnable () +{ + return m_bEnable; +} + +void +CButton::SetEnable (bool bEnable) +{ + m_bEnable = bEnable; +} + +bool +CButton::GetHide () +{ + return m_bHide; +} + +void +CButton::SetHide (bool bHide) +{ + m_bHide = bHide; +} + +// Traitement d'un événement. + +bool +CButton::TreatEvent (const SDL_Event & event) +{ + Point pos; + + if (m_bHide || !m_bEnable) + return false; + + // pos = ConvLongToPos(lParam); + + switch (event.type) + { + case SDL_MOUSEBUTTONDOWN: + if ( + event.button.button != SDL_BUTTON_LEFT && + event.button.button != SDL_BUTTON_RIGHT) + break; + + pos.x = event.button.x; + pos.y = event.button.y; + if (MouseDown (pos)) + return true; + break; + + case SDL_MOUSEMOTION: + pos.x = event.motion.x; + pos.y = event.motion.y; + if (MouseMove (pos)) + return true; + break; + + case SDL_MOUSEBUTTONUP: + if ( + event.button.button != SDL_BUTTON_LEFT && + event.button.button != SDL_BUTTON_RIGHT) + break; + + pos.x = event.button.x; + pos.y = event.button.y; + if (MouseUp (pos)) // (*) + return false; + break; + } + + return false; +} + +// (*) Tous les boutons doivent recevoir l'événement BUTTONUP ! + +// Indique si la souris est sur ce bouton. + +bool +CButton::MouseOnButton (Point pos) +{ + return Detect (pos); +} + +bool +CButton::IsInMenu (const Point & pos) +{ + Sint32 width = m_dim.x; + + if (m_nbMenu > 1 && m_bMouseDown) // submenu expanded ? + width += 2 + (m_dim.x + (IsRightReading () ? 1 : -1)) * m_nbMenu; + + if (IsRightReading () && m_nbMenu > 1 && m_bMouseDown) + { + if (pos.x > m_pos.x + m_dim.x || pos.x < m_pos.x - width + m_dim.x) + return false; + } + else + { + if (pos.x < m_pos.x || pos.x > m_pos.x + width) + return false; + } + + if (pos.y < m_pos.y || pos.y > m_pos.y + m_dim.y) + return false; + + return true; +} + +// Retourne le tooltips pour un bouton, en fonction +// de la position de la souris. + +const char * +CButton::GetToolTips (Point pos) +{ + Sint32 rank; + + if (m_bHide || !m_bEnable) + return nullptr; + + if (!this->IsInMenu (pos)) + return nullptr; + + rank = (pos.x - (m_pos.x + 2 + 1)) / (m_dim.x - 1); + if (rank < 0) + rank = 0; + if (rank > m_nbToolTips) + return nullptr; + + if (m_nbMenu > 1) + { + if (m_bMouseDown && rank > 0) + rank--; + else + rank = m_selMenu; + } + + return gettext (m_toolTips[rank]); +} + +// Détecte si la souris est dans le bouton. + +bool +CButton::Detect (Point pos) +{ + if (m_bHide || !m_bEnable) + return false; + + return this->IsInMenu (pos); +} + +// Bouton de la souris pressé. + +bool +CButton::MouseDown (Point pos) +{ + if (!Detect (pos)) + return false; + + m_mouseState = 1; + m_bMouseDown = true; + + CEvent::PushUserEvent (EV_UPDATE); + + m_pSound->PlayImage (SOUND_CLICK, pos); + return true; +} + +// Souris déplacés. + +bool +CButton::MouseMove (Point pos) +{ + bool bDetect; + Sint32 iState, iMenu; + + iState = m_mouseState; + iMenu = m_selMenu; + + bDetect = Detect (pos); + + if (m_bMouseDown) + { + if (bDetect) + m_mouseState = 1; // pressé + else + m_mouseState = m_state; + } + else + { + if (bDetect) + m_mouseState = m_state + 2; // survollé + else + m_mouseState = m_state; + } + + if ( + m_nbMenu > 1 && m_bMouseDown && + (IsRightReading () ? pos.x < m_pos.x + : pos.x > m_pos.x + m_dim.x + 2)) // in sub-menu ? + { + m_selMenu = IsRightReading () + ? (m_pos.x - 2 - pos.x) / (m_dim.x + 1) + : (pos.x - (m_pos.x + m_dim.x + 2)) / (m_dim.x - 1); + if (m_selMenu >= m_nbMenu) + m_selMenu = m_nbMenu - 1; + } + + if (iState != m_mouseState || iMenu != m_selMenu) + CEvent::PushUserEvent (EV_UPDATE); + + return m_bMouseDown; +} + +// Bouton de la souris relâché. + +bool +CButton::MouseUp (Point pos) +{ + bool bDetect; + + bDetect = Detect (pos); + + m_mouseState = m_state; + m_bMouseDown = false; + + if (!bDetect) + return false; + + if (m_message != static_cast (-1)) + CEvent::PushUserEvent (m_message); + + return true; +} diff --git a/src/button.h b/src/button.h new file mode 100644 index 0000000..bc991d3 --- /dev/null +++ b/src/button.h @@ -0,0 +1,89 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2019, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include + +#include "blupi.h" + +class CSound; +class CDecor; +class CPixmap; + +class CButton +{ +public: + CButton (); + ~CButton (); + + bool Create ( + CPixmap * pPixmap, CSound * pSound, Point pos, Sint32 type, Sint32 * pMenu, + Sint32 nbMenu, const char ** pToolTips, Sint32 region, Uint32 message, + bool isRightReading); + void Draw (); + + Sint32 GetState (); + void SetState (Sint32 state); + + Sint32 GetMenu (); + void SetMenu (Sint32 menu); + + bool GetEnable (); + void SetEnable (bool bEnable); + + bool GetHide (); + void SetHide (bool bHide); + + bool TreatEvent (const SDL_Event & event); + bool MouseOnButton (Point pos); + + const char * GetToolTips (Point pos); + +protected: + bool Detect (Point pos); + bool IsInMenu (const Point & pos); + bool MouseDown (Point pos); + bool MouseMove (Point pos); + bool MouseUp (Point pos); + +protected: + CPixmap * m_pPixmap; + CDecor * m_pDecor; + CSound * m_pSound; + + Sint32 m_type; // type de bouton + bool m_bEnable; // true si bouton actif + bool m_bHide; // true si bouton caché + Uint32 m_message; // message envoyé si bouton actionné + Point m_pos; // up/left corner + Point m_dim; // dimensions + Sint32 m_state; // 0=relâché, 1=pressé, +2=survollé + Sint32 m_mouseState; // 0=relâché, 1=pressé, +2=survollé + Sint32 m_iconMenu[20]; // icônes du sous-menu + + const char ** m_toolTips; // info-bulles + + Sint32 m_nbMenu; // nb de case du sous-menu + Sint32 m_nbToolTips; // nb d'info-bulles + Sint32 m_selMenu; // sous-menu sélectionné + + bool m_bMouseDown; // true -> bouton souris pressé +}; diff --git a/src/config.h.in b/src/config.h.in new file mode 100644 index 0000000..e242b04 --- /dev/null +++ b/src/config.h.in @@ -0,0 +1,25 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#define PB_VERSION_MAJOR @PB_VERSION_MAJOR@ +#define PB_VERSION_MINOR @PB_VERSION_MINOR@ +#define PB_VERSION_PATCH @PB_VERSION_PATCH@ +#define PB_VERSION_EXTRA "@PB_VERSION_EXTRA@" +#define PB_BINDIR "@CMAKE_INSTALL_BINDIR@" diff --git a/src/decblupi.cxx b/src/decblupi.cxx new file mode 100644 index 0000000..94fb19f --- /dev/null +++ b/src/decblupi.cxx @@ -0,0 +1,4728 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include + +#include "action.h" +#include "decgoal.h" +#include "decor.h" +#include "def.h" +#include "gettext.h" +#include "misc.h" + +// Cette table donne l'action à effectuer pour un bouton +// enfoncé. +const Sint16 table_actions[] = { + EV_ACTION_GO, EV_ACTION_STOP, EV_ACTION_EAT, EV_ACTION_CARRY, + EV_ACTION_DROP, EV_ACTION_ABAT1, EV_ACTION_ROC1, EV_ACTION_CULTIVE, + EV_ACTION_BUILD1, EV_ACTION_BUILD2, EV_ACTION_BUILD3, EV_ACTION_BUILD4, + EV_ACTION_BUILD5, EV_ACTION_BUILD6, EV_ACTION_WALL, EV_ACTION_PALIS, + EV_ACTION_ABAT1, EV_ACTION_ROC1, EV_ACTION_BRIDGEE, EV_ACTION_TOWER, + EV_ACTION_DRINK, EV_ACTION_LABO, EV_ACTION_FLOWER1, EV_ACTION_FLOWER1, + EV_ACTION_DYNAMITE, EV_ACTION_BOATE, EV_ACTION_DJEEP, EV_ACTION_FLAG, + EV_ACTION_EXTRAIT, EV_ACTION_FABJEEP, EV_ACTION_FABMINE, EV_ACTION_FABDISC, + EV_ACTION_REPEAT, EV_ACTION_DARMURE, EV_ACTION_FABARMURE, +}; + +// Supprime tous les blupi. + +void +CDecor::BlupiFlush () +{ + Sint32 i; + + memset (m_blupi, 0, sizeof (Blupi) * MAXBLUPI); + + for (i = 0; i < MAXBLUPI; i++) + m_blupi[i].bExist = false; +} + +// Crée un nouveau blupi, et retourne son rang. + +Sint32 +CDecor::BlupiCreate ( + Point cel, Sint32 action, Sint32 direct, Sint32 perso, Sint32 energy) +{ + Sint32 rank; + + if ( + perso == 0 && action == ACTION_STOP && // blupi ? + energy <= MAXENERGY / 4) + action = ACTION_STOPTIRED; + + if (perso == 1 && action == ACTION_STOP) // araignée ? + action = ACTION_S_STOP; + + if (perso == 2 && action == ACTION_STOP) // virus ? + action = ACTION_V_STOP; + + if (perso == 3 && action == ACTION_STOP) // tracks ? + action = ACTION_T_STOP; + + if (perso == 4 && action == ACTION_STOP) // robot ? + action = ACTION_R_STOP; + + if (perso == 5 && action == ACTION_STOP) // bombe ? + action = ACTION_B_STOP; + + if (perso == 7 && action == ACTION_STOP) // électro ? + action = ACTION_E_STOP; + + if (perso == 8 && action == ACTION_STOP) // disciple ? + action = ACTION_D_STOP; + + for (rank = 0; rank < MAXBLUPI; rank++) + { + if ( + m_blupi[rank].bExist && m_blupi[rank].cel.x == cel.x && + m_blupi[rank].cel.y == cel.y) + { + m_blupi[rank].aDirect = ((m_blupi[rank].aDirect / 16 + 1) % 8) * 16; + m_blupi[rank].sDirect = m_blupi[rank].aDirect; + m_blupi[rank].perso = perso; + m_blupi[rank].energy = energy; + m_blupi[rank].action = action; + BlupiActualise (rank); + return rank; + } + } + + for (rank = 0; rank < MAXBLUPI; rank++) + { + if (!m_blupi[rank].bExist) + { + m_blupi[rank].bExist = true; + m_blupi[rank].bHili = false; + m_blupi[rank].perso = perso; + m_blupi[rank].energy = energy; + m_blupi[rank].goalAction = 0; + m_blupi[rank].goalCel.x = -1; + m_blupi[rank].goalCel.y = -1; + m_blupi[rank].cel = cel; + m_blupi[rank].fix = cel; + m_blupi[rank].action = action; + m_blupi[rank].interrupt = 1; + m_blupi[rank].aDirect = direct; + m_blupi[rank].sDirect = direct; + m_blupi[rank].phase = 0; + m_blupi[rank].step = rank * 13; // un peu de hazard ! + m_blupi[rank].channel = -1; + m_blupi[rank].icon = -1; + m_blupi[rank].lastIcon = -1; + m_blupi[rank].pos.x = 0; + m_blupi[rank].pos.y = 0; + m_blupi[rank].posZ = 0; + m_blupi[rank].takeChannel = -1; + m_blupi[rank].passCel.x = -1; + m_blupi[rank].jaugePhase = -1; + m_blupi[rank].jaugeMax = -1; + m_blupi[rank].stop = 0; + m_blupi[rank].bArrow = false; + m_blupi[rank].bRepeat = false; + m_blupi[rank].bMalade = false; + m_blupi[rank].bCache = false; + m_blupi[rank].vehicule = 0; + m_blupi[rank].busyCount = 0; + m_blupi[rank].busyDelay = 0; + m_blupi[rank].clicCount = 0; + m_blupi[rank].clicDelay = 0; + + ListFlush (rank); + FlushUsed (rank); + BlupiDestCel (rank); + BlupiPushFog (rank); + BlupiActualise (rank); + return rank; + } + } + + return -1; +} + +// Supprime un blupi existant. +// Si perso == -1, supprime n'importe quel personnage ici. +// Si perso >= 0, supprime seulement ce personnage. + +bool +CDecor::BlupiDelete (Point cel, Sint32 perso) +{ + Sint32 rank; + + for (rank = 0; rank < MAXBLUPI; rank++) + { + if ( + m_blupi[rank].bExist && m_blupi[rank].cel.x == cel.x && + m_blupi[rank].cel.y == cel.y && + (perso == -1 || m_blupi[rank].perso == perso)) + { + m_blupi[rank].bExist = false; + + if (!m_bBuild) // phase de jeu ? + { + if (perso == 6) // détonnateur invisible ? + { + MoveFinish (rank); // stoppe décompte à rebourd + } + if (m_nbBlupiHili > 0 && m_rankBlupiHili == rank) // est-ce le blupi + // sélectionné ? + { + m_nbBlupiHili = 0; + m_rankBlupiHili = -1; + } + } + return true; + } + } + + return false; +} + +// Supprime un blupi existant. + +void +CDecor::BlupiDelete (Sint32 rank) +{ + m_blupi[rank].bExist = false; + this->m_pSound->StopSound (true, rank); + + if ( + !m_bBuild && // phase de jeu ? + m_nbBlupiHili > 0 && + m_rankBlupiHili == rank) // est-ce le blupi sélectionné ? + { + m_nbBlupiHili = 0; + m_rankBlupiHili = -1; + } +} + +// Supprime tout dans un périmètre donné suite à une explosion. +// type=0 -> explosion +// type=1 -> électro + +void +CDecor::BlupiKill (Sint32 exRank, Point cel, Sint32 type) +{ + Sint32 rank, action, x, y, icon; + + for (rank = 0; rank < MAXBLUPI; rank++) + { + // Supprime sans condition les blupi placés + // dans la cellule où a lieu l'explosion. + if ( + rank != exRank && m_blupi[rank].bExist && + m_blupi[rank].vehicule != 3 && // pas armure ? + !m_bInvincible && m_blupi[rank].cel.x >= cel.x && + m_blupi[rank].cel.x <= cel.x + 1 && m_blupi[rank].cel.y >= cel.y && + m_blupi[rank].cel.y <= cel.y + 1) + { + GoalUnwork (rank); + + if (type == 0) // explosion ? + { + m_blupi[rank].bExist = false; // mort instantannée + this->m_pSound->StopSound (true, rank); + } + + if (type == 1) // électro ? + { + x = m_blupi[rank].cel.x; + y = m_blupi[rank].cel.y; + icon = m_decor[x / 2][y / 2].objectIcon; + if ( + m_blupi[rank].perso == 0 && m_blupi[rank].vehicule == 0 && // à pied ? + !m_bInvincible && icon != 113 && // maison ? + icon != 28 && icon != 29 && // laboratoire ? + icon != 119 && icon != 120 && // usine ? + icon != 121 && icon != 122) // mine de fer ? + { + if (m_blupi[rank].bMalade) + action = EV_ACTION_ELECTROm; + else + action = EV_ACTION_ELECTRO; + GoalStart (rank, action, m_blupi[rank].cel); + //? BlupiChangeAction(rank, ACTION_ELECTRO); + } + } + } + + // Supprime les blupi placés une case autour de la + // cellule où a lieu l'explosion, seulement s'ils + // ne sont pas cachés (pas dans un batiment). + if ( + type == 0 && rank != exRank && m_blupi[rank].bExist && + m_blupi[rank].vehicule != 3 && // pas armure ? + !m_bInvincible && !m_blupi[rank].bCache && // pas dans un batiment ? + m_blupi[rank].cel.x >= cel.x - 1 && m_blupi[rank].cel.x <= cel.x + 2 && + m_blupi[rank].cel.y >= cel.y - 1 && m_blupi[rank].cel.y <= cel.y + 2) + { + GoalUnwork (rank); + m_blupi[rank].bExist = false; + } + } +} + +// Test si un blupi existe. + +bool +CDecor::BlupiIfExist (Sint32 rank) +{ + return !!m_blupi[rank].bExist; +} + +// Triche pour tous les blupi. +// #1 -> (POWER) redonne l'énergie maximale +// #2 -> (LONESOME) tue toutes les araignées/virus/etc. + +void +CDecor::BlupiCheat (Sint32 cheat) +{ + Sint32 rank; + + for (rank = 0; rank < MAXBLUPI; rank++) + { + if (cheat == 1) // power ? + { + if (m_blupi[rank].bExist && m_blupi[rank].perso == 0) + { + m_blupi[rank].energy = MAXENERGY; + m_blupi[rank].bMalade = false; + } + } + + if (cheat == 2) // lonesome ? + { + if ( + m_blupi[rank].bExist && m_blupi[rank].perso != 0 && + m_blupi[rank].perso != 8) // araignée/virus/etc. ? + m_blupi[rank].bExist = false; + } + } +} + +// Actualise un blupi pour pouvoir le dessiner dans son état. + +void +CDecor::BlupiActualise (Sint32 rank) +{ + Sounds sound; + + Action ( + m_blupi[rank].action, m_blupi[rank].aDirect, m_blupi[rank].phase, + m_blupi[rank].step, m_blupi[rank].channel, m_blupi[rank].icon, + m_blupi[rank].pos, m_blupi[rank].posZ, sound); + BlupiAdaptIcon (rank); + + m_blupi[rank].lastIcon = -1; + m_blupi[rank].phase = 0; + m_blupi[rank].pos.x = 0; + m_blupi[rank].pos.y = 0; + m_blupi[rank].posZ = 0; +} + +// Adapte une icône. + +void +CDecor::BlupiAdaptIcon (Sint32 rank) +{ + Sint32 direct; + + if (m_blupi[rank].icon == -1) + return; + + if (m_blupi[rank].bMalade) // malade ? + { + if (m_blupi[rank].icon >= 69 && m_blupi[rank].icon <= 92) + { + m_blupi[rank].icon += 100; // 169..192 (tout vert) + } + else if (m_blupi[rank].icon == 270) // écrasé ? + m_blupi[rank].icon = 271; + else if ( + m_blupi[rank].icon < 318 || // pas télétransporté ? + m_blupi[rank].icon > 321) + { + direct = GetIconDirect (m_blupi[rank].icon); + if (direct < 0) + { + m_blupi[rank].icon = 169; // debout direction est ! + } + else + m_blupi[rank].icon = 169 + 3 * (direct / 16); + } + } + + if (m_blupi[rank].perso == 0 && m_blupi[rank].vehicule == 1) // en bateau ? + { + direct = GetIconDirect (m_blupi[rank].icon); + if (direct < 0) + { + m_blupi[rank].icon = 234; // bateau direction est ! + } + else + m_blupi[rank].icon = 234 + (direct / (16 / 2)); + } + + if (m_blupi[rank].perso == 0 && m_blupi[rank].vehicule == 2) // en jeep ? + { + direct = GetIconDirect (m_blupi[rank].icon); + if (direct < 0) + { + m_blupi[rank].icon = 250; // bateau direction est ! + } + else + m_blupi[rank].icon = 250 + (direct / (16 / 2)); + } + + if (m_blupi[rank].perso == 0 && m_blupi[rank].vehicule == 3) // armure ? + { + if (m_blupi[rank].icon < 322 || m_blupi[rank].icon > 347) + { + if ( + m_blupi[rank].icon == 106 || // élan pour saut ? + m_blupi[rank].icon == 194) // mèche ? + m_blupi[rank].icon = 347; + else + { + direct = GetIconDirect (m_blupi[rank].icon); + if (direct < 0) + { + m_blupi[rank].icon = 322; // armure direction est ! + } + else + m_blupi[rank].icon = 322 + 3 * (direct / 16); + } + } + } + + if (m_blupi[rank].perso == 8) // disciple ? + { + direct = GetIconDirect (m_blupi[rank].icon); + if (direct < 0) + { + m_blupi[rank].icon = 290; // disciple direction est ! + } + else + m_blupi[rank].icon = 290 + (direct / (16 / 2)); + } +} + +// Fait entendre un son pour un blupi. +// Si bStop=true, on stoppe le son précédent associé +// à ce blupi (rank), si nécessaire. + +void +CDecor::BlupiSound (Sint32 rank, Sounds sound, Point pos, bool bStop) +{ + Sounds newSound; + + if (rank == -1) + rank = m_rankBlupiHili; + + if (rank != -1 && m_blupi[rank].perso == 8) // disciple ? + { + if ( + sound == SOUND_HOP || sound == SOUND_BURN || sound == SOUND_TCHAO || + sound == SOUND_FLOWER || sound == SOUND_ARROSE) + newSound = SOUND_NONE; + else + newSound = sound; + + if ( + sound == SOUND_BOING || sound == SOUND_BOING1 || sound == SOUND_BOING2 || + sound == SOUND_BOING3) + newSound = SOUND_D_BOING; + if ( + sound == SOUND_GO1 || sound == SOUND_GO2 || sound == SOUND_GO3 || + sound == SOUND_GO4 || sound == SOUND_GO5 || sound == SOUND_GO6) + newSound = SOUND_D_GO; + if ( + sound == SOUND_OK1 || sound == SOUND_OK2 || sound == SOUND_OK3 || + sound == SOUND_OK4 || sound == SOUND_OK5 || sound == SOUND_OK6 || + sound == SOUND_OK1f || sound == SOUND_OK2f || sound == SOUND_OK3f || + sound == SOUND_OK1e || sound == SOUND_OK2e || sound == SOUND_OK3e) + newSound = SOUND_D_OK; + if ( + sound == SOUND_TERM1 || sound == SOUND_TERM2 || sound == SOUND_TERM3 || + sound == SOUND_TERM4 || sound == SOUND_TERM5 || sound == SOUND_TERM6) + newSound = SOUND_D_TERM; + + if (newSound == SOUND_NONE) + return; + sound = newSound; + } + + if (bStop) + m_pSound->PlayImage (sound, pos, rank, bStop); + else + m_pSound->PlayImage (sound, pos, rank); +} + +// Sons associés à des actions. +static const struct { + Sint16 action; + Sounds sound; +} tableSound[] = { + {ACTION_BURN, SOUND_BURN}, {ACTION_TCHAO, SOUND_TCHAO}, + {ACTION_EAT, SOUND_EAT}, {ACTION_DRINK, SOUND_DRINK}, + {ACTION_SLIDE, SOUND_SLIDE}, {ACTION_R_LOAD, SOUND_R_LOAD}, +}; + +// Effectue quelques initialisations pour une nouvelle action. + +void +CDecor::BlupiInitAction (Sint32 rank, Sint32 action, Sint32 direct) +{ + Point pos; + Sint32 rand; + + for (size_t i = 0; i < countof (tableSound); ++i) + { + if (tableSound[i].action == action) + { + pos = ConvCelToPos (m_blupi[rank].cel); + BlupiSound (rank, tableSound[i].sound, pos); + break; + } + } + + m_blupi[rank].action = action; + + if (m_blupi[rank].perso == 0) // blupi ? + { + if (m_blupi[rank].vehicule == 1) // en bateau ? + { + if (m_blupi[rank].action == ACTION_STOP) + m_blupi[rank].action = ACTION_STOPb; + + if (m_blupi[rank].action == ACTION_WALK) + m_blupi[rank].action = ACTION_MARCHEb; + } + + if (m_blupi[rank].vehicule == 2) // en jeep ? + { + if (m_blupi[rank].action == ACTION_STOP) + m_blupi[rank].action = ACTION_STOPJEEP; + + if (m_blupi[rank].action == ACTION_WALK) + m_blupi[rank].action = ACTION_WALKJEEP; + } + + if (m_blupi[rank].vehicule == 3) // armure ? + { + if (m_blupi[rank].action == ACTION_STOP) + m_blupi[rank].action = ACTION_STOPARMOR; + + if (m_blupi[rank].action == ACTION_WALK) + { + m_blupi[rank].action = ACTION_WALKARMOR; + m_blupi[rank].step = (m_blupi[rank].step / 2) * 2; + } + } + + if (m_blupi[rank].energy <= MAXENERGY / 4) // peu de forces ? + { + if (m_blupi[rank].action == ACTION_STOP) + m_blupi[rank].action = ACTION_STOPTIRED; + + if (m_blupi[rank].action == ACTION_WALK) + { + m_blupi[rank].action = ACTION_WALKTIRED; + m_blupi[rank].step = (m_blupi[rank].step / 2) * 2; + } + } + + if ( + m_blupi[rank].action == ACTION_STOP && + m_blupi[rank].goalAction == 0) // à pied ? + { + rand = Random (0, 400); + if (rand >= 10 && rand <= 15 && m_blupi[rank].takeChannel == -1) + { + m_blupi[rank].action = ACTION_MISC1; // épaules + m_blupi[rank].step = 0; + } + if (rand >= 20 && rand <= 23) + { + m_blupi[rank].action = ACTION_MISC2; // grat-grat + m_blupi[rank].step = 0; + } + if (rand == 30 && m_blupi[rank].takeChannel == -1) + { + m_blupi[rank].action = ACTION_MISC3; // yoyo + m_blupi[rank].step = 0; + } + if (rand >= 40 && rand <= 45) + { + m_blupi[rank].action = ACTION_MISC4; // ferme les yeux + m_blupi[rank].step = 0; + } + if (rand == 50 && m_blupi[rank].takeChannel == -1) + { + m_blupi[rank].action = ACTION_MISC5; // ohé + m_blupi[rank].step = 0; + } + if (rand == 60) + { + m_blupi[rank].action = ACTION_MISC6; // diabolo + m_blupi[rank].step = 0; + } + } + if ( + m_blupi[rank].action == ACTION_STOPTIRED && m_blupi[rank].goalAction == 0) + { + rand = Random (0, 100); + if ( + rand == 10 && // propabilité 1/100 + m_blupi[rank].takeChannel == -1) + { + m_blupi[rank].action = ACTION_MISC1f; + m_blupi[rank].step = 0; + } + } + + if (direct != -1) + m_blupi[rank].sDirect = direct; + + if ( + m_blupi[rank].action == ACTION_BUILD || + m_blupi[rank].action == ACTION_BUILDBREF || + m_blupi[rank].action == ACTION_BUILDSEC || + m_blupi[rank].action == ACTION_BUILDSOURD || + m_blupi[rank].action == ACTION_BUILDPIERRE || + m_blupi[rank].action == ACTION_PICKAXE || + m_blupi[rank].action == ACTION_PIOCHEPIERRE || + m_blupi[rank].action == ACTION_PIOCHESOURD || + m_blupi[rank].action == ACTION_ARROSE || + m_blupi[rank].action == ACTION_BECHE || + m_blupi[rank].action == ACTION_SAW || + m_blupi[rank].action == ACTION_CARRY || + m_blupi[rank].action == ACTION_DROP || + m_blupi[rank].action == ACTION_BURN || + m_blupi[rank].action == ACTION_TCHAO || + m_blupi[rank].action == ACTION_GRILL1 || + m_blupi[rank].action == ACTION_GRILL2 || + m_blupi[rank].action == ACTION_GRILL3 || + m_blupi[rank].action == ACTION_ELECTRO || + m_blupi[rank].action == ACTION_EAT || + m_blupi[rank].action == ACTION_DRINK || + m_blupi[rank].action == ACTION_BORN || + m_blupi[rank].action == ACTION_JUMPJEEP || + m_blupi[rank].action == ACTION_JUMP2 || + m_blupi[rank].action == ACTION_JUMP3 || + m_blupi[rank].action == ACTION_JUMP4 || + m_blupi[rank].action == ACTION_JUMP5 || + //? m_blupi[rank].action == ACTION_GLISSE || + m_blupi[rank].action == ACTION_BRIDGE || + m_blupi[rank].action == ACTION_MECHE || + m_blupi[rank].action == ACTION_S_GRILL || + m_blupi[rank].action == ACTION_V_GRILL || + m_blupi[rank].action == ACTION_T_CRUSHED || + m_blupi[rank].action == ACTION_R_WALK || + m_blupi[rank].action == ACTION_R_APLAT || + m_blupi[rank].action == ACTION_R_BUILD || + m_blupi[rank].action == ACTION_R_LOAD || + m_blupi[rank].action == ACTION_B_WALK || + m_blupi[rank].action == ACTION_E_WALK || + m_blupi[rank].action == ACTION_MARCHEb || + m_blupi[rank].action == ACTION_WALKJEEP || + m_blupi[rank].action == ACTION_TELEPORTE1 || + m_blupi[rank].action == ACTION_TELEPORTE2 || + m_blupi[rank].action == ACTION_TELEPORTE3 || + m_blupi[rank].action == ACTION_ARMOROPEN || + m_blupi[rank].action == ACTION_ARMORCLOSE) + m_blupi[rank].step = 0; + } + + if (m_blupi[rank].perso == 1) // araignée ? + { + if (m_blupi[rank].action == ACTION_WALK) + m_blupi[rank].action = ACTION_S_WALK; + + if (m_blupi[rank].action == ACTION_STOP) + { + m_blupi[rank].action = ACTION_S_STOP; + m_blupi[rank].sDirect = Random (0, 7) * 16; + } + + m_blupi[rank].step = 0; + } + + if (m_blupi[rank].perso == 2) // virus ? + { + if (m_blupi[rank].action == ACTION_WALK) + m_blupi[rank].action = ACTION_V_WALK; + + if (m_blupi[rank].action == ACTION_STOP) + m_blupi[rank].action = ACTION_V_STOP; + + m_blupi[rank].step = 0; + } + + if (m_blupi[rank].perso == 3) // tracks ? + { + if (m_blupi[rank].action == ACTION_WALK) + m_blupi[rank].action = ACTION_T_WALK; + + if (m_blupi[rank].action == ACTION_STOP) + m_blupi[rank].action = ACTION_T_STOP; + + m_blupi[rank].step = 0; + } + + if (m_blupi[rank].perso == 4) // robot ? + { + if (m_blupi[rank].action == ACTION_WALK) + m_blupi[rank].action = ACTION_R_WALK; + + if (m_blupi[rank].action == ACTION_STOP) + m_blupi[rank].action = ACTION_R_STOP; + + m_blupi[rank].step = 0; + } + + if (m_blupi[rank].perso == 5) // bombe ? + { + if (m_blupi[rank].action == ACTION_WALK) + m_blupi[rank].action = ACTION_B_WALK; + + if (m_blupi[rank].action == ACTION_STOP) + m_blupi[rank].action = ACTION_B_STOP; + + m_blupi[rank].step = 0; + } + + if (m_blupi[rank].perso == 7) // électro ? + { + if (m_blupi[rank].action == ACTION_WALK) + m_blupi[rank].action = ACTION_E_WALK; + + if (m_blupi[rank].action == ACTION_STOP) + m_blupi[rank].action = ACTION_E_STOP; + + m_blupi[rank].step = 0; + } + + if (m_blupi[rank].perso == 8) // disciple ? + { + if (direct != -1) + m_blupi[rank].sDirect = direct; + + if (m_blupi[rank].action == ACTION_WALK) + m_blupi[rank].action = ACTION_D_WALK; + + if (m_blupi[rank].action == ACTION_STOP) + m_blupi[rank].action = ACTION_D_STOP; + + if ( + m_blupi[rank].action == ACTION_PICKAXE || + m_blupi[rank].action == ACTION_BUILDSEC || + m_blupi[rank].action == ACTION_BUILDBREF) + m_blupi[rank].action = ACTION_D_PICKAXE; + + if (m_blupi[rank].action == ACTION_BUILD) + m_blupi[rank].action = ACTION_D_BUILD; + + if ( + m_blupi[rank].action == ACTION_SAW || + m_blupi[rank].action == ACTION_BUILDSOURD || + m_blupi[rank].action == ACTION_PIOCHESOURD) + m_blupi[rank].action = ACTION_D_SAW; + + if (m_blupi[rank].action == ACTION_TCHAO) + m_blupi[rank].action = ACTION_D_TCHAO; + + if (m_blupi[rank].action == ACTION_CUEILLE1) + m_blupi[rank].action = ACTION_D_CUEILLE1; + + if (m_blupi[rank].action == ACTION_CUEILLE2) + m_blupi[rank].action = ACTION_D_CUEILLE2; + + if (m_blupi[rank].action == ACTION_MECHE) + m_blupi[rank].action = ACTION_D_MECHE; + + if (m_blupi[rank].action == ACTION_ARROSE) + m_blupi[rank].action = ACTION_D_ARROSE; + + if (m_blupi[rank].action == ACTION_BECHE) + m_blupi[rank].action = ACTION_D_BECHE; + + m_blupi[rank].step = 0; + } +} + +// Change l'action de blupi. + +void +CDecor::BlupiChangeAction (Sint32 rank, Sint32 action, Sint32 direct) +{ + if (rank < 0) + return; + + BlupiInitAction (rank, action, direct); + BlupiDestCel (rank); + m_blupi[rank].phase = 0; + m_blupi[rank].pos.x = 0; + m_blupi[rank].pos.y = 0; + BlupiNextAction (rank); +} + +// Vide la liste des actions. + +void +CDecor::ListFlush (Sint32 rank) +{ + Sint32 i; + + for (i = 0; i < MAXLIST; i++) + m_blupi[rank].listButton[i] = BUTTON_NONE; + m_blupi[rank].repeatLevelHope = -1; + m_blupi[rank].repeatLevel = -1; +} + +// Retourne le paramètre associé à une action. + +Sint32 +CDecor::ListGetParam (Sint32 rank, Buttons button, Point cel) +{ + Sint32 icon; + + if (button == BUTTON_CARRY || button == BUTTON_FLOWER) + return m_decor[cel.x / 2][cel.y / 2].objectIcon; + + if (button == BUTTON_DEPOSE) + return m_blupi[rank].takeIcon; + + if (button == BUTTON_GO && cel.x % 2 == 1 && cel.y % 2 == 1) + { + icon = m_decor[cel.x / 2][cel.y / 2].objectIcon; + if ( + icon == 117 || // bateau ? + icon == 118) // voiture ? + return icon; + } + + return -1; +} + +// Ajoute une action dans la liste. + +bool +CDecor::ListPut (Sint32 rank, Buttons button, Point cel, Point cMem) +{ + Sint32 i, last; + + if (button == BUTTON_REPEAT || button == BUTTON_GO) + return true; + + // Mémorise "mange" seulement après un "cultive". + if (button == BUTTON_EAT && m_blupi[rank].listButton[0] != BUTTON_CULTIVE) + return true; + + // Si prend/dépose à la suite au même endroit, + // il est inutile de mémoriser ! + last = m_blupi[rank].listButton[0]; + if ( + (button == BUTTON_CARRY && last == BUTTON_DEPOSE) || + (button == BUTTON_DEPOSE && last == BUTTON_CARRY)) + { + if ( + cel.x / 2 == m_blupi[rank].listCel[0].x / 2 && + cel.y / 2 == m_blupi[rank].listCel[0].y / 2) + { + ListRemove (rank); + return true; + } + } + + for (i = MAXLIST - 1; i > 0; i--) + { + m_blupi[rank].listButton[i] = m_blupi[rank].listButton[i - 1]; + m_blupi[rank].listCel[i] = m_blupi[rank].listCel[i - 1]; + m_blupi[rank].listParam[i] = m_blupi[rank].listParam[i - 1]; + } + + m_blupi[rank].listButton[0] = button; + m_blupi[rank].listCel[0] = cMem; + m_blupi[rank].listParam[0] = ListGetParam (rank, button, cel); + + return true; +} + +// Enlève la dernière action ajoutée dans la liste. + +void +CDecor::ListRemove (Sint32 rank) +{ + Sint32 i; + + if (m_blupi[rank].listButton[0] == BUTTON_CULTIVE) + return; + + for (i = 0; i < MAXLIST - 1; i++) + { + m_blupi[rank].listButton[i] = m_blupi[rank].listButton[i + 1]; + m_blupi[rank].listCel[i] = m_blupi[rank].listCel[i + 1]; + m_blupi[rank].listParam[i] = m_blupi[rank].listParam[i + 1]; + } + + m_blupi[rank].listButton[MAXLIST - 1] = BUTTON_NONE; +} + +// Cherche une action à répéter dans la liste. +// Retourne la profondeur de la répétition. +// Retourne -1 si aucune répétiton n'est possible. + +Sint32 +CDecor::ListSearch ( + Sint32 rank, Buttons button, Point cel, const char *& textForButton) +{ + Sint32 i, j, param, nb; + + static const char * errors[] = { + /* 0 */ translate ("1: Grow tomatoes\n2: Eat"), + /* 1 */ translate ("1: Make a bunch\n2: Transform"), + /* 2 */ translate ("1: Take\n2: Transform"), + /* 3 */ translate ("1: Extract iron\n2: Make a bomb"), + /* 4 */ translate ("1: Extract iron\n2: Make a Jeep"), + /* 5 */ translate ("1: Extract iron\n2: Make an armour"), + /* 6 */ translate ("1: Cut down a tree \n2: Make a palisade"), + /* 7 */ translate ("1: Take\n2: Build palisade"), + /* 8 */ translate ("1: Cut down a tree \n2: Build a bridge"), + /* 9 */ translate ("1: Take\n2: Build a bridge"), + /* 10 */ translate ("1: Cut down a tree \n2: Make a boat"), + /* 11 */ translate ("1: Take\n2: Make a boat"), + }; + + static Sint32 table_series[] = { + 0, // errors + 2, BUTTON_CULTIVE, BUTTON_EAT, + + 1, // errors + 4, BUTTON_FLOWER, BUTTON_CARRY, BUTTON_LABO, BUTTON_DEPOSE, + + 2, // errors + 3, BUTTON_CARRY, BUTTON_LABO, BUTTON_DEPOSE, + + 3, // errors + 3, BUTTON_EXTRAIT, BUTTON_FABMINE, BUTTON_DEPOSE, + + 4, // errors + 3, BUTTON_EXTRAIT, BUTTON_FABJEEP, BUTTON_DJEEP, + + 5, // errors + 3, BUTTON_EXTRAIT, BUTTON_MAKEARMOR, BUTTON_DARMOR, + + 6, // errors + 4, BUTTON_ABAT, BUTTON_CARRY, BUTTON_DEPOSE, BUTTON_PALIS, + + 7, // errors + 3, BUTTON_CARRY, BUTTON_DEPOSE, BUTTON_PALIS, + + 8, // errors + 4, BUTTON_ABAT, BUTTON_CARRY, BUTTON_DEPOSE, BUTTON_BRIDGE, + + 9, // errors + 3, BUTTON_CARRY, BUTTON_DEPOSE, BUTTON_BRIDGE, + + 10, // errors + 4, BUTTON_ABAT, BUTTON_CARRY, BUTTON_DEPOSE, BUTTON_BOAT, + + 11, // errors + 3, BUTTON_CARRY, BUTTON_DEPOSE, BUTTON_BOAT, + + -1, + }; + + param = ListGetParam (rank, button, cel); + + i = 0; + while (table_series[i] != -1) + { + nb = table_series[i + 1]; + if ( + button == m_blupi[rank].listButton[nb - 1] && + param == m_blupi[rank].listParam[nb - 1] && + cel.x >= m_blupi[rank].listCel[nb - 1].x - 50 && + cel.x <= m_blupi[rank].listCel[nb - 1].x + 50 && + cel.y >= m_blupi[rank].listCel[nb - 1].y - 50 && + cel.y <= m_blupi[rank].listCel[nb - 1].y + 50) + { + for (j = 0; j < nb; j++) + { + if (table_series[i + 2 + j] != m_blupi[rank].listButton[nb - 1 - j]) + goto next; + } + textForButton = gettext (errors[table_series[i]]); + return nb - 1; + } + + next: + i += nb + 2; + } + +#if 0 + for (i = 0 ; i < MAXLIST ; i++) + { + if (button == m_blupi[rank].listButton[i] && + param == m_blupi[rank].listParam[i] && + cel.x >= m_blupi[rank].listCel[i].x - 50 && + cel.x <= m_blupi[rank].listCel[i].x + 50 && + cel.y >= m_blupi[rank].listCel[i].y - 50 && + cel.y <= m_blupi[rank].listCel[i].y + 50) + return i; + } +#endif + + return -1; +} + +// Ajuste une action à répéter. + +bool +CDecor::RepeatAdjust ( + Sint32 rank, Sint32 button, Point & cel, Point & cMem, Sint32 param, + Sint32 list) +{ + Sint32 i, channel, icon, icon1, icon2, flags; + Point test; + + static Sint32 table_object[] = { + BUTTON_ABAT, + CHOBJECT, + 6, + 11, + BUTTON_ROC, + CHOBJECT, + 37, + 43, + BUTTON_EAT, + CHOBJECT, + 60, + 60, + BUTTON_PALIS, + CHOBJECT, + 36, + 36, + BUTTON_BOAT, + CHOBJECT, + 36, + 36, + BUTTON_DEPOSE, + -1, + -1, + -1, + BUTTON_DJEEP, + -1, + -1, + -1, + BUTTON_DARMOR, + -1, + -1, + -1, + 0, + }; + + static Sint32 table_mur[] = { + +2, 0, // 1<<0 + 0, +2, // 1<<1 + -2, 0, // 1<<2 + 0, -2, // 1<<3 + }; + + if ( + button == BUTTON_DEPOSE && // dépose pour une palissade ? + list > 0 && m_blupi[rank].listButton[list - 1] == BUTTON_PALIS) + { + icon = m_decor[cel.x / 2][cel.y / 2].objectIcon; + + flags = 0; + if (icon == 65) + flags = (1 << 0) | (1 << 2); + if (icon == 66) + flags = (1 << 1) | (1 << 3); + if (icon == 67) + flags = (1 << 0) | (1 << 1); + if (icon == 68) + flags = (1 << 1) | (1 << 2); + if (icon == 69) + flags = (1 << 2) | (1 << 3); + if (icon == 70) + flags = (1 << 0) | (1 << 3); + if (icon == 71) + { + for (i = 0; i < 4; i++) + { + test.x = cel.x + table_mur[i * 2 + 0]; + test.y = cel.y + table_mur[i * 2 + 1]; + if ( + IsValid (test) && + m_decor[test.x / 2][test.y / 2].floorIcon == 15 && // dalle grise ? + CelOkForAction (test, EV_ACTION_DROP, rank) == 0) + { + cel = test; + cMem = test; + goto ok; + } + } + flags = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3); + } + + if (flags == 0) + { + if (CelOkForAction (cel, EV_ACTION_DROP, rank) == 0) + goto ok; + } + + for (i = 0; i < 4; i++) + { + if (flags & (1 << i)) + { + test.x = cel.x + table_mur[i * 2 + 0]; + test.y = cel.y + table_mur[i * 2 + 1]; + if (CelOkForAction (test, EV_ACTION_DROP, rank) == 0) + { + cel = test; + cMem = test; + goto ok; + } + } + } + return false; + } + + if ( + button == BUTTON_DEPOSE && // dépose pour un bateau ? + list > 0 && m_blupi[rank].listButton[list - 1] == BUTTON_BOAT) + { + if (SearchOtherBateau (rank, cel, 100, test, icon)) + { + cel = test; + cMem = test; + goto ok; + } + return false; + } + + //? if ( button == BUTTON_MANGE ) + //? { + //? cel = m_blupi[rank].cel; // cherche là où est blupi ! + //? } + + i = 0; + channel = -2; + icon1 = -1; + icon2 = -1; + while (table_object[i] != 0) + { + if (button == table_object[i]) + { + channel = table_object[i + 1]; + icon1 = table_object[i + 2]; + icon2 = table_object[i + 3]; + break; + } + i += 4; + } + + if (button == BUTTON_CARRY || button == BUTTON_FLOWER) + { + channel = CHOBJECT; + icon1 = param; + icon2 = param; + } + if ( + button == BUTTON_GO && // va en bateau/jeep ? + param != -1) + { + channel = CHOBJECT; + icon1 = param; + icon2 = param; + } + + if (channel != -2) + { + if (!SearchOtherObject ( + rank, cel, table_actions[button], 50 * 2, channel, icon1, icon2, -1, + -1, cel, icon1)) + return false; + } + + if (button == BUTTON_PALIS) + cMem = cel; + +ok: + if (cel.x % 2 == 0) + cel.x++; + if (cel.y % 2 == 0) + cel.y++; // sur l'objet + + m_blupi[rank].interrupt = 1; + return true; +} + +// Démarre une action. + +void +CDecor::GoalStart (Sint32 rank, Sint32 action, Point cel) +{ + m_blupi[rank].goalHili = cel; + m_blupi[rank].goalAction = action; + m_blupi[rank].goalPhase = 0; + m_blupi[rank].goalCel.x = -1; + m_blupi[rank].bRepeat = false; + + GoalInitJauge (rank); + FlushUsed (rank); +} + +// Effectue la méta opération suivante. +// Retourne false lorsque c'est fini ! + +bool +CDecor::GoalNextPhase (Sint32 rank) +{ + Sint16 * pTable; + Sint32 i, nb; + + if (m_blupi[rank].goalAction == 0) + return false; + + pTable = GetTableGoal (m_blupi[rank].goalAction); + if (pTable == nullptr) + { + GoalStop (rank, true); + return false; + } + + for (i = 0; i < m_blupi[rank].goalPhase; i++) + { + if (*pTable == 0) + return false; + pTable += 1 + table_goal_nbop[*pTable]; + } + + if (*pTable == GOAL_GROUP) + { + m_blupi[rank].goalPhase++; + nb = pTable[1]; + pTable += 2; + + for (i = 0; i < nb; i++) + { + m_blupi[rank].goalPhase++; + if (!GoalNextOp (rank, pTable)) + return false; + pTable += 1 + table_goal_nbop[*pTable]; + } + } + + m_blupi[rank].goalPhase++; + return GoalNextOp (rank, pTable); +} + +// Initialise la jauge pour une méta opération. + +void +CDecor::GoalInitJauge (Sint32 rank) +{ + Sint16 * pTable; + Sint32 max = 0, op; + + m_blupi[rank].jaugePhase = -1; + m_blupi[rank].jaugeMax = -1; + + if (m_blupi[rank].perso != 0 && m_blupi[rank].perso != 8) + return; // araignée/virus/etc. ? + if (m_blupi[rank].goalAction == 0) + return; + + pTable = GetTableGoal (m_blupi[rank].goalAction); + if (pTable == nullptr) + goto term; + + while (true) + { + op = *pTable; + if (op == 0 || op == GOAL_TERM) + goto term; + + if (op == GOAL_ACTION && pTable[1] != ACTION_STOP) + max++; + + pTable += 1 + table_goal_nbop[*pTable]; + } + +term: + if (max > 0) + { + m_blupi[rank].jaugePhase = 0; + m_blupi[rank].jaugeMax = max; + } +} + +// Permet de passer à travers certains arbres. + +void +CDecor::GoalInitPassCel (Sint32 rank) +{ + Point cel; + Sint32 channel, icon; + + cel.x = (m_blupi[rank].goalCel.x / 2) * 2; + cel.y = (m_blupi[rank].goalCel.y / 2) * 2; + + GetObject (cel, channel, icon); + + if ( + channel == CHOBJECT && + ((icon >= 8 && icon <= 11) || // arbres touffus ? + (icon >= 30 && icon <= 35) || // arbres touffus sans feuilles ? + (icon >= 37 && icon <= 43) || // rochers ? + (icon == 81 || icon == 83 || icon == 94) || // fleurs ? + (icon >= 100 && icon <= 105) || // usine ? + (icon == 115 || icon == 116) || // usine ? + (icon == 17 || icon == 18) || // usine ? + (icon == 117) || // bateau ? + (icon == 118) || // jeep ? + (icon == 16))) // armure ? + m_blupi[rank].passCel = m_blupi[rank].goalCel; + else + m_blupi[rank].passCel.x = -1; +} + +// Ajuste une coordonnée de cellule. + +void +CDecor::GoalAdjustCel (Sint32 rank, Sint32 & x, Sint32 & y) +{ + if (x == -10 && y == -10) + { + if (m_blupi[rank].goalAction == EV_ACTION_BRIDGEEL) + { + x = m_blupi[rank].fix.x + m_blupi[rank].cLoop * 2; + y = m_blupi[rank].fix.y; + return; + } + if (m_blupi[rank].goalAction == EV_ACTION_BRIDGEOL) + { + x = m_blupi[rank].fix.x - m_blupi[rank].cLoop * 2; + y = m_blupi[rank].fix.y; + return; + } + if (m_blupi[rank].goalAction == EV_ACTION_BRIDGESL) + { + x = m_blupi[rank].fix.x; + y = m_blupi[rank].fix.y + m_blupi[rank].cLoop * 2; + return; + } + if (m_blupi[rank].goalAction == EV_ACTION_BRIDGENL) + { + x = m_blupi[rank].fix.x; + y = m_blupi[rank].fix.y - m_blupi[rank].cLoop * 2; + return; + } + } + + x += m_blupi[rank].cel.x; + y += m_blupi[rank].cel.y; +} + +// Liste des buts multiples. + +Sint32 table_multi_goal[16 * 2] = { + 0, 0, +1, 0, 0, +1, +1, +1, 0, -1, +1, -1, 0, +2, +1, +2, + -1, -1, -1, 0, -1, +1, -1, +2, +2, -1, +2, 0, +2, +1, +2, +2, +}; + +// Effectue une méta opération. + +bool +CDecor::GoalNextOp (Sint32 rank, Sint16 * pTable) +{ + Sint32 op, x, y; + Sint32 action, direct, channel, icon, mchannel, micon; + Sint32 total, step, delai, first, last, first2, last2, flag, i; + Sint32 param; + Buttons button; + Point pos, cel, cMem, destCel; + bool bOK, bError = true; + + pos = ConvCelToPos (m_blupi[rank].cel); + + op = *pTable++; + + if (op == GOAL_ACTION && *pTable != ACTION_STOP) + m_blupi[rank].jaugePhase++; + + if (op == GOAL_GOHILI) + { + m_blupi[rank].goalCel.x = m_blupi[rank].goalHili.x + (*pTable++); + m_blupi[rank].goalCel.y = m_blupi[rank].goalHili.y + (*pTable++); + flag = *pTable++; + //? m_blupi[rank].passCel.x = -1; + FlushUsed (rank); + return true; + } + + if (op == GOAL_GOHILI2) + { + cel.x = (m_blupi[rank].goalHili.x / 2) * 2 + (*pTable++); + cel.y = (m_blupi[rank].goalHili.y / 2) * 2 + (*pTable++); + flag = *pTable++; + if (!!flag) + { + m_blupi[rank].goalCel = cel; + GoalInitPassCel (rank); + } + m_blupi[rank].goalCel = cel; + FlushUsed (rank); + return true; + } + + if (op == GOAL_GOBLUPI) + { + cel.x = m_blupi[rank].cel.x + (*pTable++); + cel.y = m_blupi[rank].cel.y + (*pTable++); + flag = *pTable++; + if (!!flag) + { + if (IsBlupiHereEx (cel, rank, false)) // destination occupée ? + { + m_blupi[rank].goalPhase--; // on attend ... + return true; + } + m_blupi[rank].goalCel = cel; + GoalInitPassCel (rank); + } + m_blupi[rank].goalCel = cel; + FlushUsed (rank); + return true; + } + + if (op == GOAL_TESTOBJECT) + { + cel.x = m_blupi[rank].cel.x + (*pTable++); + cel.y = m_blupi[rank].cel.y + (*pTable++); + channel = *pTable++; + icon = *pTable++; + GetObject (cel, mchannel, micon); + if (channel != mchannel || icon != micon) + goto error; + return true; + } + + if (op == GOAL_PUTFLOOR) + { + x = *pTable++; + y = *pTable++; + GoalAdjustCel (rank, x, y); + channel = *pTable++; + icon = *pTable++; + if (icon == -2) + icon = m_blupi[rank].vIcon; + PutFloor (GetCel (x, y), channel, icon); + return true; + } + + if (op == GOAL_PUTOBJECT) + { + x = *pTable++; + y = *pTable++; + GoalAdjustCel (rank, x, y); + channel = *pTable++; + icon = *pTable++; + if (channel == -3 && icon == -3) // l'objet transporté ? + { + channel = m_blupi[rank].takeChannel; + icon = m_blupi[rank].takeIcon; + } + PutObject (GetCel (x, y), channel, icon); + return true; + } + + if (op == GOAL_BUILDFLOOR) + { + x = *pTable++; + y = *pTable++; + GoalAdjustCel (rank, x, y); + cel.x = (x / 2) * 2; + cel.y = (y / 2) * 2; + GetFloor (cel, channel, i); + channel = *pTable++; + icon = *pTable++; + mchannel = *pTable++; + micon = *pTable++; + total = *pTable++; + delai = *pTable++; + step = *pTable++; + + if ( + i >= 19 && i <= 32 && // herbe foncée ? + icon == 57) + icon = 58; // sol tomate foncé + if (i == 58 && icon == 1) + icon = 20; // remet herbe foncée + + if (!MoveCreate ( + cel, rank, true, channel, icon, mchannel, micon, total, delai, step)) + goto error; + return true; + } + + if (op == GOAL_BUILDOBJECT) + { + x = *pTable++; + y = *pTable++; + GoalAdjustCel (rank, x, y); + cel.x = (x / 2) * 2; + cel.y = (y / 2) * 2; + channel = *pTable++; + icon = *pTable++; + mchannel = *pTable++; + micon = *pTable++; + total = *pTable++; + delai = *pTable++; + step = *pTable++; + if (channel == -2 && icon == -2) // l'objet actuel ? + GetObject (cel, channel, icon); + ArrangeBuild (cel, channel, icon); // arrange les murs autour + if (!MoveCreate ( + cel, rank, false, channel, icon, mchannel, micon, total, delai, step)) + goto error; + return true; + } + + if (op == GOAL_FINISHMOVE) + { + MoveFinish (rank); + return true; + } + + if (op == GOAL_ARRANGEOBJECT) + { + x = *pTable++; + y = *pTable++; + GoalAdjustCel (rank, x, y); + MoveFinish (GetCel (x, y)); + ArrangeObject (GetCel (x, y)); + return true; + } + + if (op == GOAL_EXPLOSE1) + { + x = *pTable++; + y = *pTable++; + GoalAdjustCel (rank, x, y); + cel = GetCel (x, y); + + BlupiKill (rank, cel, 0); + MoveFinish (cel); + + // Faut-il démarrer une explosion en chaîne. + GetObject (cel, channel, icon); + if (channel == CHOBJECT && icon == 85) // dynamite ? + { + rank = BlupiCreate ( + GetCel (cel, 1, 1), ACTION_STOP, DIRECT_E, 6, + MAXENERGY); // crée un détonnateur + if (rank >= 0) + { + GoalStart (rank, EV_ACTION_T_DYNAMITE, cel); + m_blupi[rank].bCache = true; + } + } + else + { + PutObject (cel, -1, -1); // supprime l'objet + ArrangeObject (cel); + } + return true; + } + + if (op == GOAL_EXPLOSE2) + { + x = *pTable++; + y = *pTable++; + GoalAdjustCel (rank, x, y); + cel = GetCel ((x / 2) * 2, (y / 2) * 2); + + GetObject (cel, channel, icon); + if (channel != CHOBJECT || icon != 85) // dynamite ? + { + channel = CHOBJECT; + icon = -1; + ArrangeBuild (cel, channel, icon); // arrange les murs autour + if (!MoveCreate (cel, rank, false, CHOBJECT, -1, -1, -1, 10, 1, -1 * 100)) + goto error; + MoveAddIcons (cel, 6); // explosion + } + return true; + } + + if (op == GOAL_ADDMOVES) + { + x = *pTable++; + y = *pTable++; + GoalAdjustCel (rank, x, y); + icon = *pTable++; + MoveAddMoves (GetCel (x, y), icon); + return true; + } + + if (op == GOAL_ADDICONS) + { + x = *pTable++; + y = *pTable++; + GoalAdjustCel (rank, x, y); + icon = *pTable++; + MoveAddIcons (GetCel (x, y), icon); + return true; + } + + if (op == GOAL_ACTION) + { + action = *pTable++; + direct = *pTable++; + BlupiInitAction (rank, action, direct); + return true; + } + + if (op == GOAL_ELECTRO) + { + x = *pTable++; + y = *pTable++; + GoalAdjustCel (rank, x, y); + cel = GetCel ((x / 2) * 2, (y / 2) * 2); + icon = *pTable++; + if (MoveCreate ( + cel, rank, true, CHFLOOR, -1, -1, -1, 100, 1, 100, false, true)) + MoveAddIcons (cel, icon); + BlupiKill (rank, cel, 1); + return true; + } + + if (op == GOAL_MALADE) + { + m_blupi[rank].bMalade = *pTable++; + return true; + } + + if (op == GOAL_WORK) + { + cel.x = m_blupi[rank].cel.x + (*pTable++); + cel.y = m_blupi[rank].cel.y + (*pTable++); + m_decor[cel.x / 2][cel.y / 2].workBlupi = rank; + return true; + } + + if (op == GOAL_INTERRUPT) + { + m_blupi[rank].interrupt = *pTable++; // change le niveau + return true; + } + + if (op == GOAL_ENERGY) + { + if (m_blupi[rank].energy <= *pTable++) + goto error; + return true; + } + + if (op == GOAL_ISNOMALADE) + { + if (m_blupi[rank].bMalade) + goto error; + return true; + } + + if (op == GOAL_TAKE) + { + cel.x = m_blupi[rank].cel.x + (*pTable++); + cel.y = m_blupi[rank].cel.y + (*pTable++); + MoveFinish (rank); + m_blupi[rank].takeChannel = m_decor[cel.x / 2][cel.y / 2].objectChannel; + m_blupi[rank].takeIcon = m_decor[cel.x / 2][cel.y / 2].objectIcon; + m_decor[cel.x / 2][cel.y / 2].objectChannel = -1; + m_decor[cel.x / 2][cel.y / 2].objectIcon = -1; + return true; + } + + if (op == GOAL_TAKEOBJECT) + { + cel.x = m_blupi[rank].cel.x + (*pTable++); + cel.y = m_blupi[rank].cel.y + (*pTable++); + channel = *pTable++; + icon = *pTable++; + m_blupi[rank].takeChannel = channel; + m_blupi[rank].takeIcon = icon; + return true; + } + + if (op == GOAL_LABO) + { + m_blupi[rank].takeChannel = CHOBJECT; + if (m_blupi[rank].takeIcon == 82) // fleurs normales ? + { + m_blupi[rank].takeIcon = 80; // bouteille + } + if (m_blupi[rank].takeIcon == 84) // fleurs foncées ? + { + m_blupi[rank].takeIcon = 85; // dynamite + } + if (m_blupi[rank].takeIcon == 95) // fleurs vertes ? + { + m_blupi[rank].takeIcon = 93; // piège + } + if (m_blupi[rank].takeIcon == 60) // tomates ? + { + m_blupi[rank].takeIcon = 92; // poison + } + return true; + } + + if (op == GOAL_CACHE) + { + m_blupi[rank].bCache = *pTable++; + if ( + *pTable++ && // bDynamite ? + m_blupi[rank].perso == 0 && m_blupi[rank].vehicule == 3 && // armure ? + !m_bInvincible) + m_blupi[rank].bCache = false; + return true; + } + + if (op == GOAL_DELETE) + { + if ( + m_blupi[rank].perso == 0 && // blupi ? + m_blupi[rank].vehicule == 3 && // armure ? + !m_bInvincible) + return true; + BlupiDelete (rank); // snif ... + return true; + } + + if (op == GOAL_DEPOSE) + { + m_blupi[rank].takeChannel = -1; + return true; + } + + if (op == GOAL_NEWBLUPI) + { + cel.x = m_blupi[rank].cel.x + (*pTable++); + cel.y = m_blupi[rank].cel.y + (*pTable++); + PutObject (cel, -1, -1); // enlève les oeufs + + rank = BlupiCreate (cel, ACTION_STOP, DIRECT_E, 0, MAXENERGY / 4); + if (rank >= 0) + { + m_blupi[rank].energy = MAXENERGY / 4; + BlupiInitAction (rank, ACTION_BORN); + } + + cel.x++; + rank = BlupiCreate (cel, ACTION_STOP, DIRECT_E, 0, MAXENERGY / 4); + if (rank >= 0) + { + m_blupi[rank].energy = MAXENERGY / 4; + BlupiInitAction (rank, ACTION_BORN); + } + + cel.x--; + cel.y++; + rank = BlupiCreate (cel, ACTION_STOP, DIRECT_E, 0, MAXENERGY / 4); + if (rank >= 0) + { + m_blupi[rank].energy = MAXENERGY / 4; + BlupiInitAction (rank, ACTION_BORN); + } + + cel.x++; + rank = BlupiCreate (cel, ACTION_STOP, DIRECT_E, 0, MAXENERGY / 4); + if (rank >= 0) + { + m_blupi[rank].energy = MAXENERGY / 4; + BlupiInitAction (rank, ACTION_BORN); + } + return true; + } + + if (op == GOAL_NEWPERSO) + { + cel.x = m_blupi[rank].cel.x + (*pTable++); + cel.y = m_blupi[rank].cel.y + (*pTable++); + icon = *pTable++; + + destCel = cel; + destCel.x++; + if (IsBlupiHereEx (destCel, rank, false)) // destination occupée ? + { + m_blupi[rank].goalPhase--; // on attend ... + return true; + } + destCel.x++; + if (IsBlupiHereEx (destCel, rank, false)) // destination occupée ? + { + destCel.y--; + if ( + icon == 5 || // bombe ? + IsBlupiHereEx (destCel, rank, false)) // destination occupée ? + { + m_blupi[rank].goalPhase--; // on attend ... + return true; + } + } + + rank = BlupiCreate (cel, ACTION_STOP, DIRECT_E, icon, MAXENERGY); + if (rank >= 0) + m_blupi[rank].goalCel = destCel; + return true; + } + + if (op == GOAL_USINEBUILD) + { + cel.x = m_blupi[rank].cel.x + (*pTable++); + cel.y = m_blupi[rank].cel.y + (*pTable++); + if (!IsUsineBuild (rank, cel)) + goto error; + return true; + } + + if (op == GOAL_USINEFREE) + { + cel.x = m_blupi[rank].cel.x + (*pTable++); + cel.y = m_blupi[rank].cel.y + (*pTable++); + if (!IsUsineFree (rank, cel)) + { + GoalStop (rank, true); + m_blupi[rank].goalCel = GetCel (cel, 1, -1); // à côté de la porte + //? m_blupi[rank].goalAction = 0; // stoppe sitôt après + //? m_blupi[rank].interrupt = 1; + //? GoalUnwork(rank); + //? FlushUsed(rank); + } + return true; + } + + if (op == GOAL_AMORCE) + { + cel.x = m_blupi[rank].cel.x + (*pTable++); + cel.y = m_blupi[rank].cel.y + (*pTable++); + if (IsBlupiHereEx (cel, rank, false)) + goto error; + // Crée un détonnateur de mine (blupi invisible). + rank = BlupiCreate (cel, ACTION_STOP, DIRECT_E, 6, MAXENERGY); + if (rank >= 0) + { + m_blupi[rank].bCache = true; // invisible + m_blupi[rank].goalAction = EV_ACTION_MINE2; + m_blupi[rank].goalPhase = 0; + m_blupi[rank].goalCel.x = -1; + m_blupi[rank].interrupt = 1; + } + return true; + } + + if (op == GOAL_VEHICULE) + { + m_blupi[rank].vehicule = *pTable++; + if ( + m_blupi[rank].vehicule != 0 && // pas à pied ? + m_blupi[rank].takeChannel != -1 && // porte qq chose ? + m_blupi[rank].energy <= MAXENERGY / 4) // faible ? + m_blupi[rank].energy = MAXENERGY / 4 + 1; + return true; + } + + if (op == GOAL_ACTUALISE) + { + BlupiActualise (rank); + return true; + } + + if (op == GOAL_SOUND) + { + icon = *pTable++; + BlupiSound (rank, static_cast (icon), pos); + return true; + } + + if (op == GOAL_REPEAT) + { + icon = *pTable++; + m_blupi[rank].bRepeat = icon; + return true; + } + + if (op == GOAL_OTHER) + { + if (!m_blupi[rank].bRepeat) + goto term; + + // Bouton stop pressé ? + if (m_blupi[rank].stop == 1) + goto term; + + channel = *pTable++; + first = *pTable++; + last = *pTable++; + first2 = *pTable++; + last2 = *pTable++; + action = *pTable++; + if (!SearchOtherObject ( + rank, m_blupi[rank].cel, action, 100, channel, first, last, first2, + last2, m_blupi[rank].goalHili, icon)) + goto term; + if (action == EV_ACTION_ABAT1 || action == EV_ACTION_ROC1) + { + action += icon - first; // EV_ACTION_ABAT1..6 + } + m_blupi[rank].goalAction = action; + m_blupi[rank].goalPhase = 0; + m_blupi[rank].goalCel.x = -1; + m_blupi[rank].interrupt = 1; + GoalInitJauge (rank); + GoalUnwork (rank); + FlushUsed (rank); + return true; + } + + if (op == GOAL_OTHERFIX) + { + if (!m_blupi[rank].bRepeat) + goto term; + + // Bouton stop pressé ? + if (m_blupi[rank].stop == 1) + goto term; + + channel = *pTable++; + first = *pTable++; + last = *pTable++; + first2 = *pTable++; + last2 = *pTable++; + action = *pTable++; + if (!SearchOtherObject ( + rank, m_blupi[rank].fix, action, 100, channel, first, last, first2, + last2, m_blupi[rank].goalHili, icon)) + goto term; + if (action == EV_ACTION_ABAT1 || action == EV_ACTION_ROC1) + { + action += icon - first; // EV_ACTION_ABAT1..6 + } + m_blupi[rank].goalAction = action; + m_blupi[rank].goalPhase = 0; + m_blupi[rank].goalCel.x = -1; + m_blupi[rank].interrupt = 1; + GoalInitJauge (rank); + GoalUnwork (rank); + FlushUsed (rank); + return true; + } + + if (op == GOAL_OTHERLOOP) + { + action = *pTable++; + if (m_blupi[rank].cLoop < m_blupi[rank].nLoop) + { + m_blupi[rank].goalAction = action; + m_blupi[rank].goalPhase = 0; + m_blupi[rank].goalCel.x = -1; + m_blupi[rank].interrupt = 1; + GoalInitJauge (rank); + GoalUnwork (rank); + FlushUsed (rank); + } + return true; + } + + if (op == GOAL_NEXTLOOP) + { + m_blupi[rank].cLoop++; + return true; + } + + if (op == GOAL_FIX) + { + m_blupi[rank].fix.x = m_blupi[rank].cel.x + (*pTable++); + m_blupi[rank].fix.y = m_blupi[rank].cel.y + (*pTable++); + return true; + } + + if (op == GOAL_FLOORJUMP) + { + channel = *pTable++; + icon = *pTable++; + action = *pTable++; + GetFloor (m_blupi[rank].cel, mchannel, micon); + if (channel == mchannel && icon == micon) + { + m_blupi[rank].goalAction = action; + m_blupi[rank].goalPhase = 0; + m_blupi[rank].goalCel.x = -1; + m_blupi[rank].interrupt = 1; + GoalInitJauge (rank); + GoalUnwork (rank); + FlushUsed (rank); + } + return true; + } + + if (op == GOAL_ADDDRAPEAU) + { + cel.x = m_blupi[rank].cel.x + (*pTable++); + cel.y = m_blupi[rank].cel.y + (*pTable++); + AddDrapeau (cel); // cellule sondée + return true; + } + + if (op == GOAL_TELEPORTE) + { + pos.x = *pTable++; + pos.y = *pTable++; + + cMem = m_blupi[rank].cel; + GetFloor (cMem, channel, icon); + PutFloor (cMem, -1, -1); + bOK = SearchOtherObject ( + rank, m_blupi[rank].cel, EV_ACTION_GO, 1000, CHFLOOR, 80, 80, -1, -1, cel, + i); + PutFloor (cMem, channel, icon); + if (!bOK) + goto error; + + cel.x += pos.x; + cel.y += pos.y; + if (IsBlupiHereEx (cel, rank, false) || !IsFreeCel (cel, rank)) + goto error; + m_blupi[rank].cel = cel; + BlupiPushFog (rank); + if (m_blupi[rank].bHili) + SetCorner (cel, true); + return true; + } + + if (op == GOAL_IFTERM) + { + cel.x = m_blupi[rank].cel.x + (*pTable++); + cel.y = m_blupi[rank].cel.y + (*pTable++); + if (!IsFreeCel (cel, rank) || IsBlupiHereEx (cel, rank, false)) + goto term; + return true; + } + + if (op == GOAL_IFDEBARQUE) + { + cel.x = m_blupi[rank].cel.x + (*pTable++); + cel.y = m_blupi[rank].cel.y + (*pTable++); + m_blupi[rank].vehicule = 0; // à pied + bOK = IsFreeCel (cel, rank) && !IsBlupiHereEx (cel, rank, false); + m_blupi[rank].vehicule = 1; // en bateau + if (!bOK) + goto term; + return true; + } + + if (op == GOAL_SKIPSKILL) + { + i = (*pTable++); + total = (*pTable++); + if (m_skill == i) + { + m_blupi[rank].goalPhase += total; // saute qq instructions + } + return true; + } + + if (op == GOAL_TERM) + { + term: + bError = false; + } + + if (op == GOAL_WAITFREE) + { + cel.x = m_blupi[rank].cel.x + (*pTable++); + cel.y = m_blupi[rank].cel.y + (*pTable++); + if (IsBlupiHereEx (cel, rank, false)) // destination occupée ? + { + m_blupi[rank].goalPhase--; // on attend ... + + rank = m_blupiHere; + if ( + m_blupi[rank].goalAction != EV_ACTION_GO && + m_blupi[rank].goalAction != EV_ACTION_ELECTRO && + m_blupi[rank].goalAction != EV_ACTION_ELECTROm) + { + destCel.x = cel.x; + destCel.y = cel.y - 1; + if (!IsBlupiHereEx (destCel, rank, false)) + { + GoalStart (rank, EV_ACTION_GO, destCel); + return true; + } + + destCel.x = cel.x + 1; + destCel.y = cel.y; + if (!IsBlupiHereEx (destCel, rank, false)) + { + GoalStart (rank, EV_ACTION_GO, destCel); + return true; + } + + destCel.x = cel.x; + destCel.y = cel.y + 1; + if (!IsBlupiHereEx (destCel, rank, false)) + { + GoalStart (rank, EV_ACTION_GO, destCel); + return true; + } + + destCel.x = cel.x + 1; + destCel.y = cel.y - 1; + if (!IsBlupiHereEx (destCel, rank, false)) + { + GoalStart (rank, EV_ACTION_GO, destCel); + return true; + } + + destCel.x = cel.x + 1; + destCel.y = cel.y + 1; + if (!IsBlupiHereEx (destCel, rank, false)) + { + GoalStart (rank, EV_ACTION_GO, destCel); + return true; + } + + if (m_blupi[rank].perso == 0) + { + if (m_blupi[rank].bMalade) + action = EV_ACTION_ELECTROm; + else + action = EV_ACTION_ELECTRO; + GoalStart (rank, action, m_blupi[rank].cel); + return true; + } + } + } + return true; + } + +error: + i = m_blupi[rank].repeatLevel; + GoalStop (rank, bError, i == -1); + if (i != -1) // répétition en cours ? + { + button = static_cast (m_blupi[rank].listButton[i]); + cMem = m_blupi[rank].listCel[i]; + param = m_blupi[rank].listParam[i]; + cel = cMem; + if (RepeatAdjust (rank, button, cel, cMem, param, i)) + { + if (IsBlupiHereEx (cel, rank, false)) // destination occupée ? + { + m_blupi[rank].repeatLevel = i; // on continue ... + GoalStart (rank, EV_ACTION_GO, m_blupi[rank].cel); // on attend ... + return true; + } + if (BlupiGoal (rank, button, cel, cMem)) + { + m_blupi[rank].repeatLevel = i; // on continue ... + return true; + } + } + } + return false; +} + +// Supprime le blocage de la cellule dans laquelle +// blupi travaille. + +void +CDecor::GoalUnwork (Sint32 rank) +{ + Sint32 x, y; + + for (x = 0; x < MAXCELX / 2; x++) + { + for (y = 0; y < MAXCELY / 2; y++) + { + if (m_decor[x][y].workBlupi == rank) + { + m_decor[x][y].workBlupi = -1; // débloque + } + } + } +} + +// Stoppe complètement une action. + +void +CDecor::GoalStop (Sint32 rank, bool bError, bool bSound) +{ + Point pos; + + static Sounds table_sound_term[] = { + SOUND_TERM1, SOUND_TERM2, SOUND_TERM3, + SOUND_TERM4, SOUND_TERM5, SOUND_TERM6, + }; + + static Sounds table_sound_boing[] = { + SOUND_BOING1, + SOUND_BOING2, + SOUND_BOING3, + }; + + if (bError && bSound) + { + ListRemove (rank); // supprime la dernière action mémorisée + } + + m_blupi[rank].goalAction = 0; + m_blupi[rank].goalPhase = 0; + m_blupi[rank].goalCel.x = -1; + m_blupi[rank].jaugePhase = -1; + m_blupi[rank].jaugeMax = -1; + m_blupi[rank].interrupt = 1; // remet le niveau normal + m_blupi[rank].busyCount = 0; + m_blupi[rank].busyDelay = 0; + m_blupi[rank].repeatLevel = -1; // stoppe la répétition + FlushUsed (rank); + MoveFinish (rank); + GoalUnwork (rank); + + // En cas d'erreur, il faut accepter de traverser la + // construction avortée (par exemple, le massif d'arbres + // dans lequel blupi se trouve, mais qui n'a pas pu + // être abattu). + if (!bError) + m_blupi[rank].passCel.x = -1; + + m_blupi[rank].stop = 0; // relâche bouton stop + + if ( + bSound && (m_blupi[rank].perso == 0 || // blupi ? + m_blupi[rank].perso == 8)) // assistant ? + { + if (bError) + { + pos.x = LXIMAGE () / 2; + pos.y = LYIMAGE () / 2; + BlupiSound ( + rank, table_sound_boing[Random (0, countof (table_sound_boing) - 1)], + pos, true); + } + else + { + pos = ConvCelToPos (m_blupi[rank].cel); + BlupiSound ( + rank, table_sound_term[Random (0, countof (table_sound_term) - 1)], pos, + true); + } + } +} + +// Teste si une cellule est déjà utilisée comme but pour +// n'importe quel blupi. + +bool +CDecor::BlupiIsGoalUsed (Point cel) +{ + Sint32 rank; + + for (rank = 0; rank < MAXBLUPI; rank++) + { + if ( + m_blupi[rank].bExist && m_blupi[rank].goalCel.x / 2 == cel.x / 2 && + m_blupi[rank].goalCel.y / 2 == cel.y / 2) + return true; + } + + return false; +} + +// Démarre ou stoppe un rayon entre deux tours. + +void +CDecor::BlupiStartStopRayon (Sint32 rank, Point startCel, Point endCel) +{ + Sint32 i, icon, icon2; + Point cel, cel2, vector, pos; + + if ( + m_blupi[rank].perso == 1 || // araignée ? + m_blupi[rank].perso == 2) // virus ? + return; + + // Stoppe un rayon. + cel.x = (endCel.x / 2) * 2; + cel.y = (endCel.y / 2) * 2; + icon = m_decor[cel.x / 2][cel.y / 2].objectIcon; + if ((icon == 10000 || icon == 10001) && MoveIsUsed (cel)) + { + if (MoveIsUsed (cel)) + { + MoveFinish (cel); + + pos = ConvCelToPos (cel); + BlupiSound (rank, SOUND_RAYON2, pos); + } + + for (i = 0; i < 4; i++) + { + vector = GetVector (i * 2 * 16); + cel.x = (endCel.x / 2) * 2 + vector.x * 2; + cel.y = (endCel.y / 2) * 2 + vector.y * 2; + icon = m_decor[cel.x / 2][cel.y / 2].objectIcon; + if (icon == 10000 || icon == 10001) + MoveFinish (cel); + } + } + + // Démarre un rayon. + cel.x = (startCel.x / 2) * 2; + cel.y = (startCel.y / 2) * 2; + cel2.x = (endCel.x / 2) * 2; + cel2.y = (endCel.y / 2) * 2; + icon = m_decor[cel.x / 2][cel.y / 2].objectIcon; + icon2 = m_decor[cel2.x / 2][cel2.y / 2].objectIcon; + if ((icon == 10000 || icon == 10001) && icon2 != 10000 && icon2 != 10001) + { + if (MoveCreate (cel, -1, false, CHOBJECT, -1, -1, -1, 9999, 1, 0, true)) + { + MoveAddIcons (cel, icon == 10000 ? 4 : 5, true); // éclairs + } + + pos = ConvCelToPos (cel); + BlupiSound (rank, SOUND_RAYON1, pos); + + for (i = 0; i < 4; i++) + { + vector = GetVector (i * 2 * 16); + cel.x = (startCel.x / 2) * 2 + vector.x * 2; + cel.y = (startCel.y / 2) * 2 + vector.y * 2; + icon = m_decor[cel.x / 2][cel.y / 2].objectIcon; + if (icon == 10000 || icon == 10001) + { + if (MoveCreate (cel, -1, false, CHOBJECT, -1, -1, -1, 9999, 1, 0, true)) + { + MoveAddIcons (cel, icon == 10000 ? 4 : 5, true); // éclairs + } + } + } + } +} + +// Tourne un blupi, si nécessaire. +// Retourne false si ce n'est pas nécessaire. + +bool +CDecor::BlupiRotate (Sint32 rank) +{ + Sint32 aDirect, sDirect, ip, in, sens = 0; + bool bOK; + Point pos; + + aDirect = m_blupi[rank].aDirect; + sDirect = m_blupi[rank].sDirect; + + if (aDirect == sDirect) + return false; + + if (sDirect > aDirect) + ip = sDirect + 0 * 16 - aDirect; + else + ip = sDirect + 8 * 16 - aDirect; + + if (aDirect > sDirect) + in = aDirect + 0 * 16 - sDirect; + else + in = aDirect + 8 * 16 - sDirect; + + if (ip == 0 || in == 0) + { + m_blupi[rank].aDirect = m_blupi[rank].sDirect; + return false; + } + + if ( + m_blupi[rank].perso == 0 && // blupi ? + m_blupi[rank].vehicule == 1) // en bateau ? + { + if (ip == in) + sens = Random (0, 1) ? 8 : 8 * 16 - 8; + if (ip < in) + sens = 8; + if (ip > in) + sens = 8 * 16 - 8; + aDirect = (aDirect + sens) % (8 * 16); + } + else if ( + m_blupi[rank].perso == 0 && // blupi ? + m_blupi[rank].vehicule == 2) // en jeep ? + { + if (ip == in) + sens = Random (0, 1) ? 8 : 8 * 16 - 8; + if (ip < in) + sens = 8; + if (ip > in) + sens = 8 * 16 - 8; + aDirect = (aDirect + sens) % (8 * 16); + } + else if ( + m_blupi[rank].perso == 0 && // blupi ? + m_blupi[rank].vehicule == 3) // armure ? + { + if (ip == in) + sens = Random (0, 1) ? 4 : 8 * 16 - 4; + if (ip < in) + sens = 4; + if (ip > in) + sens = 8 * 16 - 4; + aDirect = (aDirect + sens) % (8 * 16); + } + else if (m_blupi[rank].perso == 3) // tracks ? + { + if (ip == in) + sens = Random (0, 1) ? 4 : 8 * 16 - 4; + if (ip < in) + sens = 4; + if (ip > in) + sens = 8 * 16 - 4; + aDirect = (aDirect + sens) % (8 * 16); + } + else if (m_blupi[rank].perso == 4) // robot ? + { + pos = ConvCelToPos (m_blupi[rank].cel); + BlupiSound (rank, SOUND_R_ROTATE, pos); + + if (ip == in) + sens = Random (0, 1) ? 2 : 8 * 16 - 2; + if (ip < in) + sens = 2; + if (ip > in) + sens = 8 * 16 - 2; + aDirect = (aDirect + sens) % (8 * 16); + } + else if (m_blupi[rank].perso == 8) // disciple ? + { + if (ip == in) + sens = Random (0, 1) ? 8 : 8 * 16 - 8; + if (ip < in) + sens = 8; + if (ip > in) + sens = 8 * 16 - 8; + aDirect = (aDirect + sens) % (8 * 16); + } + else + { + if (ip == in) + sens = Random (0, 1) ? 1 : 7; + if (ip < in) + sens = 1; + if (ip > in) + sens = 7; + aDirect = ((aDirect / 16 + sens) % 8) * 16; + } + + m_blupi[rank].lastIcon = m_blupi[rank].icon; + bOK = Rotate (m_blupi[rank].icon, aDirect); + if (bOK) + { + m_blupi[rank].aDirect = aDirect; + return true; + } + else + { + m_blupi[rank].aDirect = m_blupi[rank].sDirect; + return false; + } +} + +// Avance un blupi existant. + +bool +CDecor::BlupiNextAction (Sint32 rank) +{ + bool bOK; + Point pos, iCel; + Sint32 a, min; + Sounds sound; + + if (!m_blupi[rank].bExist) + return false; + + if (!g_restoreBugs) + { + /* Check if a Blupi is already doing a conflicting action at the same place. + * It happens for example when a blupi wants to carry an object from a + * direction and a second from the other direction. Without this check, the + * object is duplicated. + */ + if ((m_blupi[rank].goalAction == EV_ACTION_CARRY || + m_blupi[rank].goalAction == EV_ACTION_EAT || + m_blupi[rank].goalAction == EV_ACTION_DRINK)) + for (int i = 0; i < MAXBLUPI; ++i) + { + if (rank == i || !m_blupi[i].bExist) + continue; + + if ( + (m_blupi[i].goalAction == EV_ACTION_CARRY2 || + m_blupi[i].goalAction == EV_ACTION_EAT2 || + m_blupi[i].goalAction == EV_ACTION_DRINK2) && + m_blupi[rank].goalHili.x == m_blupi[i].goalHili.x && + m_blupi[rank].goalHili.y == m_blupi[i].goalHili.y) + { + BlupiInitAction (i, ACTION_STOP); + GoalStop (i, true); + return false; + } + } + + /* Prevent Blupi to take a trap when an enemy is already captured. */ + if (m_blupi[rank].perso == 0 && m_blupi[rank].action == ACTION_CARRY) + { + Sint32 ch, icon; + + auto exists = this->GetObject (m_blupi[rank].goalHili, ch, icon); + if (exists && ch == CHOBJECT) + { + switch (icon) + { + case 96: // spider in trap + case 97: // track in trap + case 98: // robot in trap + BlupiInitAction (rank, ACTION_STOP); + GoalStop (rank, true); + return false; + + default: + break; + } + } + } + } + + if (m_blupi[rank].clicDelay > 0) + m_blupi[rank].clicDelay--; + if (m_blupi[rank].clicDelay == 0) + m_blupi[rank].clicCount = 0; + + bOK = true; + if (!BlupiRotate (rank)) // si rotation pas nécessaire + { + m_blupi[rank].lastIcon = m_blupi[rank].icon; + + bOK = Action ( + m_blupi[rank].action, m_blupi[rank].aDirect, m_blupi[rank].phase, + m_blupi[rank].step, m_blupi[rank].channel, m_blupi[rank].icon, + m_blupi[rank].pos, m_blupi[rank].posZ, sound); + BlupiAdaptIcon (rank); + + if (sound != SOUND_NONE) + { + pos = ConvCelToPos (m_blupi[rank].cel); + BlupiSound (rank, sound, pos); + } + } + + a = GetAmplitude (m_blupi[rank].action); + + iCel = m_blupi[rank].cel; + + if ( + m_blupi[rank].pos.x == (DIMCELX / 2) * a && + m_blupi[rank].pos.y == (DIMCELY / 2) * a) + { + m_blupi[rank].cel.x += a; + BlupiPushFog (rank); + BlupiStartStopRayon (rank, iCel, m_blupi[rank].cel); + } + + if ( + m_blupi[rank].pos.x == -(DIMCELX / 2) * a && + m_blupi[rank].pos.y == -(DIMCELY / 2) * a) + { + m_blupi[rank].cel.x -= a; + BlupiPushFog (rank); + BlupiStartStopRayon (rank, iCel, m_blupi[rank].cel); + } + + if ( + m_blupi[rank].pos.x == -(DIMCELX / 2) * a && + m_blupi[rank].pos.y == (DIMCELY / 2) * a) + { + m_blupi[rank].cel.y += a; + BlupiPushFog (rank); + BlupiStartStopRayon (rank, iCel, m_blupi[rank].cel); + } + + if ( + m_blupi[rank].pos.x == (DIMCELX / 2) * a && + m_blupi[rank].pos.y == -(DIMCELY / 2) * a) + { + m_blupi[rank].cel.y -= a; + BlupiPushFog (rank); + BlupiStartStopRayon (rank, iCel, m_blupi[rank].cel); + } + + if (m_blupi[rank].pos.x == 0 && m_blupi[rank].pos.y == DIMCELY * a) + { + m_blupi[rank].cel.x += a; + m_blupi[rank].cel.y += a; + BlupiPushFog (rank); + BlupiStartStopRayon (rank, iCel, m_blupi[rank].cel); + } + + if (m_blupi[rank].pos.x == 0 && m_blupi[rank].pos.y == -DIMCELY * a) + { + m_blupi[rank].cel.x -= a; + m_blupi[rank].cel.y -= a; + BlupiPushFog (rank); + BlupiStartStopRayon (rank, iCel, m_blupi[rank].cel); + } + + if (m_blupi[rank].pos.x == DIMCELX * a && m_blupi[rank].pos.y == 0) + { + m_blupi[rank].cel.x += a; + m_blupi[rank].cel.y -= a; + BlupiPushFog (rank); + BlupiStartStopRayon (rank, iCel, m_blupi[rank].cel); + } + + if (m_blupi[rank].pos.x == -DIMCELX * a && m_blupi[rank].pos.y == 0) + { + m_blupi[rank].cel.x -= a; + m_blupi[rank].cel.y += a; + BlupiPushFog (rank); + BlupiStartStopRayon (rank, iCel, m_blupi[rank].cel); + } + + // Blupi perd de l'énergie s'il fait qq chose. + if ( + m_blupi[rank].action != ACTION_STOP && + m_blupi[rank].action != ACTION_STOPTIRED && + m_blupi[rank].action != ACTION_STOPb && + m_blupi[rank].action != ACTION_STOPJEEP && + m_blupi[rank].action != ACTION_MISC1 && + m_blupi[rank].action != ACTION_MISC2 && + m_blupi[rank].action != ACTION_MISC3 && + m_blupi[rank].action != ACTION_MISC4 && + m_blupi[rank].action != ACTION_MISC5 && + m_blupi[rank].action != ACTION_MISC6 && + m_blupi[rank].action != ACTION_MISC1f) + { + if ( + m_blupi[rank].energy > 0 && m_blupi[rank].perso == 0 && // blupi ? + m_blupi[rank].vehicule == 0) // à pied ? + { + if (m_bSuper) + a = 0; + else + a = 1; + min = 0; + if ( + m_blupi[rank].action != ACTION_WALK && + (m_blupi[rank].goalAction == EV_ACTION_WALL || + m_blupi[rank].goalAction == EV_ACTION_TOWER)) + { + a = 5; + min = 1; + } + if (m_blupi[rank].action == ACTION_SLIDE) + { + if (m_bSuper) + a = 0; + else + a = 40; + } + m_blupi[rank].energy -= a; // blupi se fatigue +/- + if (m_blupi[rank].energy < min) + m_blupi[rank].energy = min; + } + } + + // Blupi prend de l'énergie s'il mange. + if (m_blupi[rank].action == ACTION_EAT) + { + if (m_blupi[rank].energy < MAXENERGY) + m_blupi[rank].energy += MAXENERGY / (40 * 3); + } + + // Le robot perd de l'énergie s'il fait qq chose. + if (m_blupi[rank].action != ACTION_R_STOP) + { + if (m_blupi[rank].energy > 0 && m_blupi[rank].perso == 4) + { + m_blupi[rank].energy -= 3; // le robot se fatigue + if (m_blupi[rank].energy < 1) + m_blupi[rank].energy = 1; + } + } + + // Le robot prend de l'énergie s'il se recharge. + if (m_blupi[rank].action == ACTION_R_LOAD) + { + if (m_blupi[rank].energy < MAXENERGY) + m_blupi[rank].energy = MAXENERGY; + } + + // Blupi guérrit s'il boit. + if (m_blupi[rank].action == ACTION_DRINK) + { + m_blupi[rank].bMalade = false; + if (m_blupi[rank].energy < MAXENERGY) + m_blupi[rank].energy += MAXENERGY / (40 * 3); + } + + // Si blupi est presque complètement épuisé, il stoppe. + if ( + !bOK && m_blupi[rank].perso == 0 && m_blupi[rank].energy < 50 && + m_blupi[rank].energy != 0 && m_blupi[rank].action == ACTION_WALKTIRED) + { + BlupiInitAction (rank, ACTION_STOP); + GoalStop (rank, true); + } + + return bOK; +} + +// Action suivante pour un blupi existant. + +void +CDecor::BlupiNextGoal (Sint32 rank) +{ + Sint32 direct, action, channel, icon, min, lg, fRank, i; + Point pos, cel, vector; + + if (!m_blupi[rank].bExist) + return; + + pos = ConvCelToPos (m_blupi[rank].cel); + + // Si blupi termine une action "mort", il doit disparaître. + if ( + m_blupi[rank].action == ACTION_BURN || + m_blupi[rank].action == ACTION_TCHAO || + m_blupi[rank].action == ACTION_S_GRILL || + m_blupi[rank].action == ACTION_V_GRILL) + { + BlupiDelete (rank); // snif ... + return; + } + + // Si blupi passe trop prêt du feu, aie aie aie ... + if (IsFireCel (m_blupi[rank].cel)) // blupi se brule les ailes ? + { + if ( + m_blupi[rank].perso == 0 && m_blupi[rank].vehicule != 3 && // pas armure ? + !m_bInvincible && m_blupi[rank].goalAction != EV_ACTION_GRILLE) + { + BlupiDeselect (rank); + GoalStart (rank, EV_ACTION_GRILLE, m_blupi[rank].cel); + goto goal; + //? BlupiInitAction(rank, ACTION_BRULE); + //? goto init; + } + if ( + m_blupi[rank].perso == 1 || // araignée ? + m_blupi[rank].perso == 2) // virus ? + { + BlupiDelete (rank); // la bestiole meurt + return; + } + } + + // Si blupi passe trop prêt d'un virus ... + if ( + m_blupi[rank].perso == 0 && + m_blupi[rank].vehicule != 1 && // pas en bateau ? + m_blupi[rank].vehicule != 3 && // pas armure ? + !m_blupi[rank].bMalade && // en bonne santé ? + m_blupi[rank].goalAction != EV_ACTION_GRILLE && + m_blupi[rank].goalAction != EV_ACTION_ELECTRO && + m_blupi[rank].goalAction != EV_ACTION_ELECTROm && + m_blupi[rank].goalAction != EV_ACTION_BOATDE && + m_blupi[rank].goalAction != EV_ACTION_BOATDS && + m_blupi[rank].goalAction != EV_ACTION_BOATDO && + m_blupi[rank].goalAction != EV_ACTION_BOATDN && + m_blupi[rank].goalAction != EV_ACTION_BOATAE && + m_blupi[rank].goalAction != EV_ACTION_BOATAS && + m_blupi[rank].goalAction != EV_ACTION_BOATAO && + m_blupi[rank].goalAction != EV_ACTION_BOATAN && !m_bInvincible && + IsVirusCel (m_blupi[rank].cel)) // blupi chope un virus ? + { + m_blupi[rank].bMalade = true; + + if (m_blupi[rank].energy > MAXENERGY / 4) + m_blupi[rank].energy = MAXENERGY / 4; + + BlupiSound (rank, SOUND_VIRUS, pos); + + if (m_blupi[rank].vehicule == 2) // en jeep ? + { + GoalStart (rank, EV_ACTION_DJEEP, m_blupi[rank].cel); + goto goal; + } + } + + // Si blupi est complètement épuisé, il meurt. + if (m_blupi[rank].perso == 0 && m_blupi[rank].energy == 0) + { + BlupiDeselect (rank); + BlupiInitAction (rank, ACTION_TCHAO); + goto init; + } + + // Assigne un but s'il s'agit d'une araignée. + if ( + m_blupi[rank].perso == 1 && // araignée ? + m_blupi[rank].goalAction != EV_ACTION_A_MORT) + { + cel = m_blupi[rank].cel; + cel.x = (cel.x / 2) * 2; + cel.y = (cel.y / 2) * 2; + GetObject (cel, channel, icon); + if ( + channel == CHOBJECT && (icon == 10000 || icon == 10001) && // rayon ? + MoveIsUsed (cel)) // enclenché ? + { + BlupiInitAction (rank, ACTION_S_GRILL); + goto init; + } + + cel = m_blupi[rank].cel; + if (cel.x % 2 != 0 && cel.y % 2 != 0) + { + cel.x = (cel.x / 2) * 2; + cel.y = (cel.y / 2) * 2; + GetObject (cel, channel, icon); + if (channel == CHOBJECT && icon == 60) // tomates ? + { + PutObject (cel, -1, -1); // plus de tomates + BlupiSound (rank, SOUND_S_HIHI, pos); + } + if (channel == CHOBJECT && icon == 92) // poison ? + { + PutObject (cel, -1, -1); // plus de poison + BlupiInitAction (rank, ACTION_STOP); + GoalStart (rank, EV_ACTION_A_MORT, m_blupi[rank].cel); + m_blupi[rank].goalCel = m_blupi[rank].cel; + goto goal; + //? BlupiSound(rank, SOUND_A_POISON, pos); + //? BlupiInitAction(rank, ACTION_A_POISON); + //? goto init; + } + if (channel == CHOBJECT && icon == 93) // piège ? + { + BlupiSound (rank, SOUND_TRAP, pos); + PutObject (cel, CHOBJECT, 96); // araignée piégée + BlupiDelete (rank); // supprime araignée + return; + } + } + + m_blupi[rank].bExist = false; + if ( + m_time % 5 == rank % 5 && // pas trop souvent ! + SearchSpiderObject (rank, m_blupi[rank].cel, 100, cel, icon)) + { + m_blupi[rank].goalCel = cel; + FlushUsed (rank); + // direct = DirectSearch(m_blupi[rank].cel, cel); + // if ( direct != -1 ) + // { + // vector = GetVector(direct); + // m_blupi[rank].goalCel.x = m_blupi[rank].cel.x + vector.x; + // m_blupi[rank].goalCel.y = m_blupi[rank].cel.y + vector.y; + // FlushUsed(rank); + // } + } + m_blupi[rank].bExist = true; + } + + // Assigne un but s'il s'agit d'un virus. + if (m_blupi[rank].perso == 2) // virus ? + { + cel = m_blupi[rank].cel; + cel.x = (cel.x / 2) * 2; + cel.y = (cel.y / 2) * 2; + GetObject (cel, channel, icon); + if ( + channel == CHOBJECT && (icon == 10000 || icon == 10001) && // rayon ? + MoveIsUsed (cel)) // enclenché ? + { + BlupiInitAction (rank, ACTION_V_GRILL); + goto init; + } + + min = 50; // ignore si trop loin ! + fRank = -1; + for (i = 0; i < MAXBLUPI; i++) + { + if (m_blupi[i].bExist && m_blupi[i].perso == 0 && !m_blupi[i].bMalade) + { + lg = abs (m_blupi[rank].cel.x - m_blupi[i].cel.x) + + abs (m_blupi[rank].cel.y - m_blupi[i].cel.y); + if (lg < min) + { + min = lg; + fRank = i; + } + } + } + if (fRank != -1) + { + direct = DirectSearch (m_blupi[rank].cel, m_blupi[fRank].cel); + if (direct != -1) + { + vector = GetVector (direct); + m_blupi[rank].goalCel.x = m_blupi[rank].cel.x + vector.x; + m_blupi[rank].goalCel.y = m_blupi[rank].cel.y + vector.y; + FlushUsed (rank); + } + } + } + + // Assigne un but s'il s'agit d'un tracks. + if ( + m_blupi[rank].perso == 3 && // tracks ? + m_blupi[rank].goalAction != EV_ACTION_T_DYNAMITE) + { + cel = m_blupi[rank].cel; + if (cel.x % 2 != 0 && cel.y % 2 != 0) + { + cel.x = (cel.x / 2) * 2; + cel.y = (cel.y / 2) * 2; + GetObject (cel, channel, icon); + if (channel == CHOBJECT && IsTracksObject (icon)) + { + if (icon == 85) // dynamite ? + { + BlupiInitAction (rank, ACTION_STOP); + GoalStart (rank, EV_ACTION_T_DYNAMITE, cel); + goto goal; + } + if ( + icon == 125 || // mine ? + icon == 127) + { + // Supprime le détonnateur. + BlupiDelete (GetCel (cel.x + 1, cel.y + 1), 6); + } + if (icon == 93) // piège ? + { + BlupiSound (rank, SOUND_TRAP, pos); + PutObject (cel, CHOBJECT, 97); // tracks piégé + BlupiDelete (rank); // supprime tracks + return; + } + + PutObject (cel, -1, -1); // plus d'objet + + BlupiSound (rank, SOUND_T_ECRASE, pos); + BlupiInitAction (rank, ACTION_T_CRUSHED); + goto init; + } + } + cel = m_blupi[rank].cel; + m_blupi[rank].bExist = false; + if ( + IsBlupiHere (cel, false) && m_blupi[m_blupiHere].perso == 0 && + m_blupi[m_blupiHere].vehicule == 0) // à pied ? + { + m_blupi[rank].bExist = true; + // Blupi écrasé au sol. + if (MoveCreate ( + cel, rank, true, CHFLOOR, -1, -1, -1, 100, 1, 100, false, true)) + { + if (m_blupi[m_blupiHere].bMalade) + MoveAddIcons (cel, 10); + else + MoveAddIcons (cel, 9); + } + BlupiDelete (m_blupiHere); // plus de blupi ! + BlupiSound (rank, SOUND_AIE, pos); + BlupiInitAction (rank, ACTION_T_CRUSHED); // écrase blupi + goto init; + } + m_blupi[rank].bExist = true; + + // if ( m_blupi[rank].goalCel.x != -1 ) + // { + // GetObject(m_blupi[rank].goalCel, channel, icon); + // if ( IsTracksObject(icon) ) goto action; + // } + m_blupi[rank].bExist = false; + if ( + m_time % 5 == rank % 5 && // pas trop souvent ! + SearchTracksObject (rank, m_blupi[rank].cel, 25, cel, icon)) + { + m_blupi[rank].goalCel = cel; + FlushUsed (rank); + } + m_blupi[rank].bExist = true; + } + + // Assigne un but s'il s'agit d'un robot. + if ( + m_blupi[rank].perso == 4 && // robot ? + m_blupi[rank].goalAction != EV_ACTION_T_DYNAMITE) + { + cel = m_blupi[rank].cel; + if (cel.x % 2 != 0 && cel.y % 2 != 0) + { + cel.x = (cel.x / 2) * 2; + cel.y = (cel.y / 2) * 2; + GetObject (cel, channel, icon); + if (channel == CHOBJECT && IsRobotObject (icon)) + { + if (icon == 85) // dynamite ? + { + BlupiInitAction (rank, ACTION_STOP); + GoalStart (rank, EV_ACTION_T_DYNAMITE, cel); + goto goal; + } + if ( + icon == 125 || // mine ? + icon == 127) + { + // Supprime le détonnateur. + BlupiDelete (GetCel (cel.x + 1, cel.y + 1), 6); + } + if (icon == 93) // piège ? + { + BlupiSound (rank, SOUND_TRAP, pos); + PutObject (cel, CHOBJECT, 98); // robot piégé + BlupiDelete (rank); // supprime robot + return; + } + + PutObject (cel, -1, -1); // plus d'objet + + BlupiSound (rank, SOUND_T_ECRASE, pos); + BlupiInitAction (rank, ACTION_R_CRUSHED); + goto init; + } + } + cel = m_blupi[rank].cel; + if ( + m_blupi[rank].goalAction == 0 && + m_time % 17 == rank % 17 && // pas trop souvent ! + SearchRobotObject (rank, m_blupi[rank].fix, 50, cel, icon, action)) + { + if (action == -1) + { + m_blupi[rank].goalCel = cel; + FlushUsed (rank); + } + else + { + BlupiInitAction (rank, ACTION_STOP); + GoalStart (rank, action, cel); + goto goal; + } + } + } + + // Assigne un but s'il s'agit d'une bombe. + if ( + m_blupi[rank].perso == 5 && // bombe ? + m_blupi[rank].goalAction != EV_ACTION_T_DYNAMITE) + { + cel = m_blupi[rank].cel; + if (cel.x % 2 != 0 && cel.y % 2 != 0) + { + cel.x = (cel.x / 2) * 2; + cel.y = (cel.y / 2) * 2; + GetObject (cel, channel, icon); + if (channel == CHOBJECT && icon == 93) // piège ? + { + BlupiSound (rank, SOUND_TRAP, pos); + PutObject (cel, CHOBJECT, 114); // bombe piégée + BlupiDelete (rank); // supprime bombe + return; + } + } + for (i = 0; i < 4; i++) + { + vector = GetVector (i * 2 * 16); + cel.x = ((m_blupi[rank].cel.x + vector.x * 2) / 2) * 2; + cel.y = ((m_blupi[rank].cel.y + vector.y * 2) / 2) * 2; + GetObject (cel, channel, icon); + if ( + channel == CHOBJECT && + IsBombeObject (icon) && // cabane, palissade, etc. ? + icon != 93) // pas piège ? + { + BlupiInitAction (rank, ACTION_STOP); + GoalStart (rank, EV_ACTION_T_DYNAMITE, m_blupi[rank].cel); + goto goal; + } + } + cel = m_blupi[rank].cel; + if ( + m_blupi[rank].goalAction == 0 && + m_time % 17 == rank % 17 && // pas trop souvent ! + SearchBombeObject (rank, cel, 100, cel, icon)) + { + m_blupi[rank].goalCel = cel; + FlushUsed (rank); + } + } + + // Assigne un but s'il s'agit d'un électro. + if (m_blupi[rank].perso == 7) // électro ? + { + cel = m_blupi[rank].cel; + if (cel.x % 2 != 0 && cel.y % 2 != 0) + { + cel.x = (cel.x / 2) * 2; + cel.y = (cel.y / 2) * 2; + GetObject (cel, channel, icon); + if (channel == CHOBJECT && icon == 93) // piège ? + { + BlupiSound (rank, SOUND_TRAP, pos); + PutObject (cel, CHOBJECT, 19); // électro piégée + BlupiDelete (rank); // supprime électro + return; + } + } + cel = m_blupi[rank].cel; + if ( + m_blupi[rank].goalAction == 0 && m_blupi[rank].goalCel.x == -1 && + m_time % 37 == rank % 37 && // pas trop souvent ! + SearchElectroObject (rank, cel, 100, cel, icon)) + { + if (icon == -1) // sur un blupi ? + { + BlupiInitAction (rank, ACTION_STOP); + GoalStart (rank, EV_ACTION_E_RAYON, cel); + m_blupi[rank].fix = cel; + goto goal; + } + m_blupi[rank].goalCel = cel; + FlushUsed (rank); + } + } + + BlupiInitAction (rank, ACTION_STOP); + +goal: + if (m_blupi[rank].goalCel.x != -1) // y a-t-il un but ? + { + direct = DirectSearch (m_blupi[rank].cel, m_blupi[rank].goalCel); + + if (direct == -1) // but atteint ? + { + m_blupi[rank].goalCel.x = -1; + FlushUsed (rank); + } + else + { + // Si blupi a peu d'énergie et qu'il transporte + // qq chose, il doit stopper ! + if ( + m_blupi[rank].energy <= MAXENERGY / 4 && + m_blupi[rank].takeChannel != -1 && + (m_blupi[rank].vehicule == 0 || // à pied ? + m_blupi[rank].vehicule == 3)) // armure ? + { + // Si blupi est en train de descendre de la jeep + // et qu'il est malade tout en transportant qq + // chose, il ne faut pas stopper !!! + cel = m_blupi[rank].cel; + if ( + cel.x % 2 != 0 && cel.y % 2 != 0 && + m_decor[cel.x / 2][cel.y / 2].objectIcon == 118 && // jeep + m_blupi[rank].bMalade && m_blupi[rank].takeChannel != -1) + goto search; + GoalStop (rank, true); + } + else + { + search: + //- BlupiInitAction(rank, ACTION_MARCHE, direct); + if (SearchBestPass (rank, action)) + { + //- if ( (action >= ACTION_SAUTE2 && + //- action <= ACTION_SAUTE5) || + //- action == ACTION_GLISSE ) + //- { + BlupiInitAction (rank, action); + //- } + } + else + { + BlupiInitAction (rank, ACTION_STOP); + if ( + m_blupi[rank].perso == 0 || // blupi ? + m_blupi[rank].perso == 8) // disciple ? + { + if (m_blupi[rank].busyCount == 0) // dernière tentative ? + { + GoalStop (rank, true); + m_blupi[rank].goalCel.x = -1; + m_blupi[rank].goalPhase = 0; + m_blupi[rank].interrupt = 1; + } + } + else // perso ennemi ? + { + // On cherchera un autre but ! + GoalStop (rank, true); + //? m_blupi[rank].goalCel.x = -1; + //? m_blupi[rank].goalPhase = 0; + //? m_blupi[rank].interrupt = 1; + } + } + } + } + } + else + { + GoalNextPhase (rank); // méta opération suivante + } + +init: + BlupiDestCel (rank); + + m_blupi[rank].phase = 0; + m_blupi[rank].pos.x = 0; + m_blupi[rank].pos.y = 0; + + BlupiNextAction (rank); +} + +// Calcule la cellule de destination. + +void +CDecor::BlupiDestCel (Sint32 rank) +{ + Sint32 a; + Point vector; + + m_blupi[rank].destCel = m_blupi[rank].cel; + + if ( + m_blupi[rank].action == ACTION_WALK || + m_blupi[rank].action == ACTION_WALKTIRED || + m_blupi[rank].action == ACTION_MARCHEb || + m_blupi[rank].action == ACTION_WALKJEEP || + m_blupi[rank].action == ACTION_WALKARMOR || + m_blupi[rank].action == ACTION_S_WALK || + m_blupi[rank].action == ACTION_V_WALK || + m_blupi[rank].action == ACTION_T_WALK || + m_blupi[rank].action == ACTION_R_WALK || + m_blupi[rank].action == ACTION_B_WALK || + m_blupi[rank].action == ACTION_E_WALK || + m_blupi[rank].action == ACTION_D_WALK) + { + vector = GetVector (m_blupi[rank].sDirect); + + m_blupi[rank].destCel.x += vector.x; + m_blupi[rank].destCel.y += vector.y; + } + + a = GetAmplitude (m_blupi[rank].action); + if (a > 1) + { + vector = GetVector (m_blupi[rank].sDirect); + + m_blupi[rank].destCel.x += vector.x * a; + m_blupi[rank].destCel.y += vector.y * a; + } +} + +// Avance tous les blupis. + +void +CDecor::BlupiStep (bool bFirst) +{ + Sint32 rank; + + for (rank = 0; rank < MAXBLUPI; rank++) + { + if (m_blupi[rank].bExist) + { + if (!BlupiNextAction (rank)) + BlupiNextGoal (rank); + } + } + + if (bFirst) + { + m_timeConst++; // avance le temps absolu global constant + + if (m_timeConst == m_timeFlipOutline) + { + m_bOutline = false; // supprime le mode "outline" + } + } + m_time++; // avance le temps absolu global +} + +// Retourne le rectangle occupé par un blupi, +// pour les sélections (pas exact). + +void +CDecor::BlupiGetRect (Sint32 rank, Rect & rect) +{ + Point pos; + + pos = ConvCelToPos (m_blupi[rank].cel); + pos.x += m_blupi[rank].pos.x; + pos.y += m_blupi[rank].pos.y - (DIMBLUPIY - DIMCELY) - SHIFTBLUPIY; + + rect.left = pos.x + 16; + rect.top = pos.y + 10; + rect.right = pos.x + DIMBLUPIX - 16; + rect.bottom = pos.y + DIMBLUPIY; +} + +// Retourne le blupi visé par la souris. + +Sint32 +CDecor::GetTargetBlupi (Point pos) +{ + Sint32 rank, found, prof; + Point test, rel, cel; + + cel = ConvPosToCel (pos); + + found = -1; + prof = 0; + for (rank = 0; rank < MAXBLUPI; rank++) + { + if ( + m_blupi[rank].bExist && (m_blupi[rank].perso == 0 || // blupi ? + m_blupi[rank].perso == 8)) // disciple ? + { + test = ConvCelToPos (m_blupi[rank].cel); + test.x += m_blupi[rank].pos.x; + test.y += m_blupi[rank].pos.y - (DIMBLUPIY - DIMCELY) - SHIFTBLUPIY; + + if ( + pos.x >= test.x && pos.x <= test.x + DIMBLUPIX && pos.y >= test.y && + pos.y <= test.y + DIMBLUPIY) + { + rel.x = pos.x - test.x; + rel.y = pos.y - test.y; + if ( + (cel.x == m_blupi[rank].cel.x && cel.y == m_blupi[rank].cel.y) || + (cel.x == m_blupi[rank].destCel.x && + cel.y == m_blupi[rank].destCel.y) || + m_pPixmap->IsIconPixel ( + m_blupi[rank].channel, m_blupi[rank].icon, rel)) + { + if (found != -1 && test.y < prof) + continue; + + found = rank; + prof = test.y; + } + } + } + } + + return found; +} + +// Déslectionne tous les blupi. + +void +CDecor::BlupiDeselect () +{ + Sint32 rank; + + for (rank = 0; rank < MAXBLUPI; rank++) + { + m_blupi[rank].bHili = false; + m_blupi[rank].bArrow = false; + } + + m_nbBlupiHili = 0; + m_rankBlupiHili = -1; +} + +// Déslectionne un blupi. + +void +CDecor::BlupiDeselect (Sint32 rank) +{ + m_blupi[rank].bHili = false; + m_blupi[rank].bArrow = false; + + if (m_nbBlupiHili > 0 && m_rankBlupiHili == rank) // est-ce le blupi + // sélectionné ? + { + m_nbBlupiHili = 0; + m_rankBlupiHili = -1; + } +} + +// Met ou enlève une flèche au blupi sélectionné blupi. + +void +CDecor::BlupiSetArrow (Sint32 rank, bool bArrow) +{ + m_celArrow.x = -1; + + if (bArrow) + m_blupi[rank].bArrow = true; + else + { + for (rank = 0; rank < MAXBLUPI; rank++) + m_blupi[rank].bArrow = false; + } +} + +// Initialise la zone outline en fonction du rectangle de sélection. + +void +CDecor::InitOutlineRect () +{ + if (!m_bOutline && m_bHiliRect) + { + m_celOutline1.x = m_p1Hili.x < m_p2Hili.x ? m_p1Hili.x : m_p2Hili.x; + m_celOutline1.y = m_p1Hili.y < m_p2Hili.y ? m_p1Hili.y : m_p2Hili.y; + m_celOutline2.x = m_p1Hili.x > m_p2Hili.x ? m_p1Hili.x : m_p2Hili.x; + m_celOutline2.y = m_p1Hili.y > m_p2Hili.y ? m_p1Hili.y : m_p2Hili.y; + m_celOutline1.x = (m_celOutline1.x / 2) * 2; + m_celOutline1.y = (m_celOutline1.y / 2) * 2; + m_celOutline2.x += 2; + m_celOutline2.y += 2; + } + else + { + m_celOutline1.x = -1; + m_celOutline2.x = -1; + } +} + +// Sélectionne un blupi lorsque le bouton est pressé. + +void +CDecor::BlupiHiliDown (Point pos, bool bAdd) +{ + if (MapMove (pos)) + return; + + if (!bAdd) + BlupiDeselect (); + + m_p1Hili = ConvPosToCel (pos); + m_p2Hili = ConvPosToCel (pos); + m_bHiliRect = true; + m_celHili.x = -1; + + InitOutlineRect (); +} + +// Sélectionne un blupi lorsque la souris est déplacée. + +void +CDecor::BlupiHiliMove (Point pos) +{ + if (m_bHiliRect) // rectangle de sélection existe ? + { + m_p2Hili = ConvPosToCel (pos); + InitOutlineRect (); + } +} + +// Sélectionne un blupi lorsque le bouton est relâché. +// Retourne false si la sélection n'a pas changé ! + +void +CDecor::BlupiHiliUp (Point pos) +{ + Sint32 rank, r, nb; + Sounds sound; + bool bEnerve = false; + Point c1, c2; + + static Sounds table_sound_ok[] = { + SOUND_OK1, SOUND_OK2, SOUND_OK3, SOUND_OK4, SOUND_OK5, SOUND_OK6, + }; + + static Sounds table_sound_okf[] = // si fatigué + { + SOUND_OK1f, + SOUND_OK2f, + SOUND_OK3f, + }; + + static Sounds table_sound_oke[] = // si énervé + { + SOUND_OK1e, + SOUND_OK2e, + SOUND_OK3e, + }; + + if (m_bHiliRect) // rectangle de sélection existe ? + { + nb = 0; + + if (m_p1Hili.x == m_p2Hili.x && m_p1Hili.y == m_p2Hili.y) + { + rank = GetTargetBlupi (pos); // rank <- blupi visé par la souris + if (rank != -1) + { + m_blupi[rank].bHili = !m_blupi[rank].bHili; + if (m_blupi[rank].bHili) + { + if (m_blupi[rank].clicDelay > 0) + { + m_blupi[rank].clicDelay = 80; + m_blupi[rank].clicCount++; + if (m_blupi[rank].clicCount > 4) + bEnerve = true; + } + else + m_blupi[rank].clicDelay = 40; + nb = 1; + } + } + } + else + { + if (m_p1Hili.x < m_p2Hili.x) + { + c1.x = m_p1Hili.x; + c2.x = m_p2Hili.x + 1; + } + else + { + c1.x = m_p2Hili.x; + c2.x = m_p1Hili.x + 1; + } + + if (m_p1Hili.y < m_p2Hili.y) + { + c1.y = m_p1Hili.y; + c2.y = m_p2Hili.y + 1; + } + else + { + c1.y = m_p2Hili.y; + c2.y = m_p1Hili.y + 1; + } + + for (r = 0; r < MAXBLUPI; r++) + { + if ( + m_blupi[r].bExist && (m_blupi[r].perso == 0 || // blupi ? + m_blupi[r].perso == 8)) // disciple ? + { + if ( + m_blupi[r].cel.x >= c1.x && m_blupi[r].cel.x < c2.x && + m_blupi[r].cel.y >= c1.y && m_blupi[r].cel.y < c2.y) + { + m_blupi[r].bHili = true; + nb++; + rank = r; + } + } + } + } + + m_bHiliRect = false; // plus de rectangle + InitOutlineRect (); + + if (nb > 0) + { + if (nb > 1) // sélection multiple ? + sound = table_sound_ok[Random (0, countof (table_sound_ok) - 1)]; + else + { + if (m_blupi[rank].energy <= MAXENERGY / 4) + sound = table_sound_okf[Random (0, countof (table_sound_okf) - 1)]; + else + sound = table_sound_ok[Random (0, countof (table_sound_ok) - 1)]; + if (bEnerve) // déjà sélectionné y'a peu ? + sound = table_sound_oke[Random (0, countof (table_sound_oke) - 1)]; + } + BlupiSound (rank, sound, pos, true); + } + } + + m_nbBlupiHili = 0; + m_rankBlupiHili = -1; + for (rank = 0; rank < MAXBLUPI; rank++) + { + m_blupi[rank].bArrow = false; + + if (m_blupi[rank].bExist && m_blupi[rank].bHili) + { + m_nbBlupiHili++; + m_rankBlupiHili = rank; + } + } +} + +// Dessine le rectangle de sélection, si nécessaire. + +void +CDecor::BlupiDrawHili () +{ + Point c1, c2, cc; + Point p1, p2, p3, p4; + Point start, pos; + Rect rect; + Sint32 shift; + + if (!m_bHiliRect) + return; + + if (m_p1Hili.x < m_p2Hili.x) + { + c1.x = m_p1Hili.x; + c2.x = m_p2Hili.x + 1; + } + else + { + c1.x = m_p2Hili.x; + c2.x = m_p1Hili.x + 1; + } + + if (m_p1Hili.y < m_p2Hili.y) + { + c1.y = m_p1Hili.y; + c2.y = m_p2Hili.y + 1; + } + else + { + c1.y = m_p2Hili.y; + c2.y = m_p1Hili.y + 1; + } + + p1 = ConvCelToPos (c1); // p1 en haut + p2 = ConvCelToPos (c2); // p2 en bas + + cc.x = c1.x; + cc.y = c2.y; + p3 = ConvCelToPos (cc); // p3 à gauche + + cc.x = c2.x; + cc.y = c1.y; + p4 = ConvCelToPos (cc); // p4 à droite + + p1.x += DIMCELX / 2; + p2.x += DIMCELX / 2; + p3.x += DIMCELX / 2; + p4.x += DIMCELX / 2; + + shift = m_shiftHili % (64 / 2); + + start.x = p1.x - shift * 2; + start.y = p1.y - shift - 1; + while (start.x < p4.x) + { + pos = start; + rect.left = 0; + rect.right = 64; + rect.top = 0; + rect.bottom = 66 / 2; + if (pos.x + rect.right > p4.x) + rect.right = p4.x - pos.x; + if (pos.x < p1.x) + { + rect.left += p1.x - pos.x; + rect.top += (p1.x - pos.x) / 2; + pos.x = p1.x; + pos.y = p1.y - 1; + } + m_pPixmap->DrawPart (-1, CHHILI, pos, rect); // ligne p1-p4 + + start.x += 64; + start.y += 64 / 2; + } + + start.x = p3.x - shift * 2; + start.y = p3.y - shift - 1; + while (start.x < p2.x) + { + pos = start; + rect.left = 0; + rect.right = 64; + rect.top = 0; + rect.bottom = 66 / 2; + if (pos.x + rect.right > p2.x) + rect.right = p2.x - pos.x; + if (pos.x < p3.x) + { + rect.left += p3.x - pos.x; + rect.top += (p3.x - pos.x) / 2; + pos.x = p3.x; + pos.y = p3.y - 1; + } + m_pPixmap->DrawPart (-1, CHHILI, pos, rect); // ligne p3-p2 + + start.x += 64; + start.y += 64 / 2; + } + + start.x = p3.x - shift * 2; + start.y = p3.y + shift - 66 / 2; + while (start.x < p1.x) + { + pos = start; + rect.left = 0; + rect.right = 64; + rect.top = 66 / 2; + rect.bottom = 66; + if (pos.x + rect.right > p1.x) + rect.right = p1.x - pos.x; + if (pos.x < p3.x) + { + rect.left += p3.x - pos.x; + rect.bottom -= (p3.x - pos.x) / 2; + pos.x = p3.x; + } + m_pPixmap->DrawPart (-1, CHHILI, pos, rect); // ligne p3-p1 + + start.x += 64; + start.y -= 64 / 2; + } + + start.x = p2.x - shift * 2; + start.y = p2.y + shift - 66 / 2; + while (start.x < p4.x) + { + pos = start; + rect.left = 0; + rect.right = 64; + rect.top = 66 / 2; + rect.bottom = 66; + if (pos.x + rect.right > p4.x) + rect.right = p4.x - pos.x; + if (pos.x < p2.x) + { + rect.left += p2.x - pos.x; + rect.bottom -= (p2.x - pos.x) / 2; + pos.x = p2.x; + } + m_pPixmap->DrawPart (-1, CHHILI, pos, rect); // ligne p2-p4 + + start.x += 64; + start.y -= 64 / 2; + } + + m_shiftHili += 3; +} + +// Retourne le bouton par défaut à un endroit donné. +// Est utilisé pour trouver que faire lors d'un clic +// avec le bouton de droite. + +Buttons +CDecor::GetDefButton (Point cel) +{ + Buttons button; + Sint32 rank, channel, icon; + Point iCel; + + iCel = cel; + cel.x = (cel.x / 2) * 2; + cel.y = (cel.y / 2) * 2; + GetObject (cel, channel, icon); + + if (m_nbBlupiHili == 0) + return BUTTON_NONE; + if (m_nbBlupiHili > 1) + return BUTTON_GO; + + rank = m_rankBlupiHili; + + button = BUTTON_GO; + + if (channel == CHOBJECT) + { + if (icon >= 6 && icon <= 11) + button = BUTTON_ABAT; + if (icon >= 37 && icon <= 43) + button = BUTTON_ROC; + + if (icon == 61) + button = BUTTON_CULTIVE; // cabane + if (icon == 81 || icon == 83 || icon == 94) + button = BUTTON_FLOWER; + if (icon == 122) + button = BUTTON_EXTRAIT; // extrait + + if (iCel.x % 2 == 1 && iCel.y % 2 == 1) + { + if (icon == 14) + button = BUTTON_CARRY; // métal + if (icon == 36) + button = BUTTON_CARRY; // planches + if (icon == 44) + button = BUTTON_CARRY; // pierres + if (icon == 60) + button = BUTTON_EAT; // tomates + if (icon == 63) + button = BUTTON_CARRY; // oeufs + if (icon == 80) + button = BUTTON_BOIT; // bouteille + if (icon == 82) + button = BUTTON_CARRY; // fleurs + if (icon == 84) + button = BUTTON_CARRY; // fleurs + if (icon == 95) + button = BUTTON_CARRY; // fleurs + if (icon == 85) + button = BUTTON_CARRY; // dynamite + if (icon == 92) + button = BUTTON_CARRY; // poison + if (icon == 93) + button = BUTTON_CARRY; // piège + if (icon == 123) + button = BUTTON_CARRY; // fer + if (icon == 125) + button = BUTTON_CARRY; // mine + } + + if ( + icon == 28 && // laboratoire ? + m_blupi[rank].energy > MAXENERGY / 4 && + m_blupi[rank].takeChannel == CHOBJECT && + (m_blupi[rank].takeIcon == 82 || // porte fleurs ? + m_blupi[rank].takeIcon == 84 || m_blupi[rank].takeIcon == 95 || + m_blupi[rank].takeIcon == 60)) // porte tomates ? + { + button = BUTTON_LABO; // transforme + } + } + + if (!m_blupi[rank].bMalade && button == BUTTON_BOIT) + { + button = BUTTON_CARRY; // porte la bouteille si pas malade + } + + if ( + (m_blupi[rank].energy <= MAXENERGY / 4 || + m_blupi[rank].takeChannel != -1) && + (button == BUTTON_ABAT || button == BUTTON_CARRY || button == BUTTON_ROC || + button == BUTTON_CULTIVE)) + return BUTTON_NONE; + + if (m_blupi[rank].energy > (MAXENERGY / 4) * 3 && button == BUTTON_EAT) + button = BUTTON_CARRY; + + if (m_buttonExist[button] == 0) // bouton existe ? + return BUTTON_NONE; + + return button; +} + +// Indique un but visé à Sint32 terme, pour un blupi donné. + +bool +CDecor::BlupiGoal (Sint32 rank, Buttons button, Point cel, Point cMem) +{ + Point goalHili, goalHili2, goal, test; + Sint32 i, action, channel, icon, error, direct, step; + bool bRepeat = false; + + // Si plusieurs blupi sont sélectionnés, ils ne vont pas + // tous à la même destination. + if (button == BUTTON_GO) + { + step = 0; + for (i = 0; i < rank; i++) + { + if (m_blupi[i].bExist && m_blupi[i].bHili) + step++; + } + if (step > 15) + step = 15; + cel.x += table_multi_goal[step * 2 + 0]; + cel.y += table_multi_goal[step * 2 + 1]; + cMem.x += table_multi_goal[step * 2 + 0]; + cMem.y += table_multi_goal[step * 2 + 1]; + } + + if (!IsCheminFree (rank, cel, button)) + return false; + + goal = cel; + goalHili = cel; + goalHili2.x = (cel.x / 2) * 2; + goalHili2.y = (cel.y / 2) * 2; + + if ( + button == BUTTON_GO && + m_decor[goalHili.x / 2][goalHili.y / 2].objectIcon == 113) // maison ? + { + goalHili.x = (goalHili.x / 2) * 2 + 1; + goalHili.y = (goalHili.y / 2) * 2 + 1; + } + + if (button == BUTTON_ABATn) + { + button = BUTTON_ABAT; + bRepeat = true; + } + if (button == BUTTON_ROCn) + { + button = BUTTON_ROC; + bRepeat = true; + } + if (button == BUTTON_FLOWERn) + { + button = BUTTON_FLOWER; + bRepeat = true; + } + action = table_actions[button]; + + if (action == EV_ACTION_STOP) + { + if (m_blupi[rank].goalAction != 0 && m_blupi[rank].interrupt <= 0) + { + m_blupi[rank].stop = 1; // faudra stopper + } + else + { + m_blupi[rank].goalCel = m_blupi[rank].destCel; + m_blupi[rank].goalAction = 0; + } + m_blupi[rank].repeatLevel = -1; // stoppe la répétition + return false; + } + + // Action prioritaire en cours ? + if (m_blupi[rank].goalAction != 0 && m_blupi[rank].interrupt <= 0) + return false; + + error = CelOkForAction (goalHili, action, rank); + if (error != 0 && error != Errors::TOURISOL) + return false; + + if ( + action == EV_ACTION_GO && m_blupi[rank].energy <= MAXENERGY / 4 && + m_blupi[rank].takeChannel != -1) + return false; + + if (action == EV_ACTION_GO) + { + GetObject (goalHili2, channel, icon); + if ( + channel == CHOBJECT && icon == 120 && // usine ? + goalHili.x % 2 == 0 && // au fond ? + goalHili.y % 2 == 1) + { + return false; // action refusée + } + if ( + m_blupi[rank].perso != 8 && // pas disciple ? + channel == CHOBJECT && icon == 118 && // jeep ? + goalHili.x % 2 == 1 && // sur la jeep ? + goalHili.y % 2 == 1) + action = EV_ACTION_MJEEP; + if ( + m_blupi[rank].perso != 8 && // pas disciple ? + m_blupi[rank].takeChannel == -1 && // ne porte rien ? + channel == CHOBJECT && icon == 16 && // armure ? + goalHili.x % 2 == 1 && // sur l'armure ? + goalHili.y % 2 == 1) + action = EV_ACTION_MARMURE; + if ( + m_blupi[rank].perso != 8 && // pas disciple ? + channel == CHOBJECT && icon == 113) // maison ? + action = EV_ACTION_HOUSE; + GetFloor (goalHili2, channel, icon); + if ( + m_blupi[rank].perso == 0 && m_blupi[rank].vehicule == 0 && // à pied ? + m_blupi[rank].takeChannel == -1 && // ne porte rien ? + channel == CHFLOOR && icon == 80) // téléporteur ? + { + if (cel.x % 2 == 0 && cel.y % 2 == 0) + action = EV_ACTION_TELEPORTE00; + if (cel.x % 2 == 1 && cel.y % 2 == 0) + action = EV_ACTION_TELEPORTE10; + if (cel.x % 2 == 0 && cel.y % 2 == 1) + action = EV_ACTION_TELEPORTE01; + if (cel.x % 2 == 1 && cel.y % 2 == 1) + action = EV_ACTION_TELEPORTE11; + } + IsFreeCelEmbarque (goalHili, rank, action, goal); + IsFreeCelDebarque (goalHili, rank, action, goal); + } + + if (action == EV_ACTION_DROP && m_blupi[rank].energy <= MAXENERGY / 4) + { + // Energie juste pour déposer l'objet transporté. + m_blupi[rank].energy = MAXENERGY / 4 + 20; + } + + if (action == EV_ACTION_ABAT1) + { + GetObject (goalHili2, channel, icon); + if (channel == CHOBJECT && icon >= 6 && icon <= 11) // arbre ? + { + action += icon - 6; // EV_ACTION_ABAT1..6 + } + } + + if (action == EV_ACTION_ROC1) + { + GetObject (goalHili2, channel, icon); + if (channel == CHOBJECT && icon >= 37 && icon <= 43) // rochers ? + { + action += icon - 37; // EV_ACTION_ROC1..7 + } + } + + if (action == EV_ACTION_FLOWER1) + { + GetObject (goalHili2, channel, icon); + if (channel == CHOBJECT && icon == 83) // fleurs foncées ? + action = EV_ACTION_FLOWER2; + if (channel == CHOBJECT && icon == 94) // fleurs vertes ? + action = EV_ACTION_FLOWER3; + } + + if (action == EV_ACTION_BRIDGEE) + { + cel = goalHili2; + test = goalHili2; + if (IsBuildPont (test, icon) != 0) + return false; + + m_blupi[rank].nLoop = + static_cast (abs ((test.x - cel.x) + (test.y - cel.y)) / 2); + m_blupi[rank].cLoop = 0; + m_blupi[rank].vIcon = icon; + m_blupi[rank].fix = cel; + + if (test.x - cel.x < 0) + action = EV_ACTION_BRIDGEO; + if (test.y - cel.y > 0) + action = EV_ACTION_BRIDGES; + if (test.y - cel.y < 0) + action = EV_ACTION_BRIDGEN; + } + + if (action == EV_ACTION_BOATE) + { + if (!IsBuildBateau (goalHili2, direct)) + return false; + + if (direct == DIRECT_S) + action = EV_ACTION_BOATS; + if (direct == DIRECT_W) + action = EV_ACTION_BOATO; + if (direct == DIRECT_N) + action = EV_ACTION_BOATN; + } + + if (action == EV_ACTION_CARRY) + { + if (IsBlupiHereEx (GetCel (goalHili2, 0, 1), rank, true)) + action = EV_ACTION_CARRY2; + } + + if (action == EV_ACTION_DROP) + { + GetFloor (goalHili2, channel, icon); + if ( + channel == CHFLOOR && icon == 52 && // nurserie ? + m_blupi[rank].takeChannel == CHOBJECT && + m_blupi[rank].takeIcon == 63) // oeufs ? + action = EV_ACTION_NEWBLUPI; + if ( + !IsFreeCelDepose (GetCel (goalHili2, 0, 1), rank) || + IsBlupiHereEx (GetCel (goalHili2, 0, 1), rank, true)) + action = EV_ACTION_DROP2; + } + + if (action == EV_ACTION_EAT) + { + if (IsBlupiHereEx (GetCel (goalHili2, 0, 1), rank, true)) + action = EV_ACTION_EAT2; + } + + if (action == EV_ACTION_DRINK) + { + if (IsBlupiHereEx (GetCel (goalHili2, 0, 1), rank, true)) + action = EV_ACTION_DRINK2; + } + + if (action == EV_ACTION_DYNAMITE) + { + GetObject (goalHili2, channel, icon); + if (channel == CHOBJECT && icon == 125) // mine ? + action = EV_ACTION_MINE; + else + { + if ( + m_blupi[rank].takeChannel == CHOBJECT && + m_blupi[rank].takeIcon == 85) // porte dynamite ? + action = EV_ACTION_DYNAMITE2; + } + } + + GoalStart (rank, action, goal); + m_blupi[rank].bRepeat = bRepeat; + m_blupi[rank].busyCount = 5; // 5 tentatives au maximum + m_blupi[rank].busyDelay = 0; + + if (action == EV_ACTION_REPEAT) + { + m_blupi[rank].repeatLevel = m_blupi[rank].repeatLevelHope; + m_blupi[rank].listCel[m_blupi[rank].repeatLevel] = goal; + } + else + ListPut (rank, button, goal, cMem); + + return true; +} + +// Indique un but visé à Sint32 terme, pour tous les blupi +// sélectionnés. + +void +CDecor::BlupiGoal (Point cel, Buttons button) +{ + Point bPos, avg; + Sint32 rank, nb, nbHili; + + static Sounds table_sound_go[] = { + SOUND_GO1, SOUND_GO2, SOUND_GO3, SOUND_GO4, SOUND_GO5, SOUND_GO6, + }; + + static Sounds table_sound_gom[] = { + SOUND_GO4, + SOUND_GO5, + SOUND_GO6, + }; + + static Sounds table_sound_boing[] = { + SOUND_BOING1, + SOUND_BOING2, + SOUND_BOING3, + }; + + if (button == -1) + { + avg = ConvCelToPos (cel); + m_pSound->PlayImage ( + table_sound_boing[Random (0, countof (table_sound_boing) - 1)], avg); + return; + } + + avg.x = 0; + avg.y = 0; + nb = 0; + nbHili = 0; + for (rank = 0; rank < MAXBLUPI; rank++) + { + if (m_blupi[rank].bExist && m_blupi[rank].bHili) + { + bPos = ConvCelToPos (m_blupi[rank].cel); + avg.x += bPos.x; + avg.y += bPos.y; + nbHili++; + + if (BlupiGoal (rank, button, cel, cel)) + nb++; + } + } + + if (button == BUTTON_STOP) + return; + + if (nbHili > 0) + { + avg.x /= nbHili; + avg.y /= nbHili; + } + if (avg.x < 0) + avg.x = 0; + if (avg.x > LXIMAGE ()) + avg.x = LXIMAGE (); + avg.y = LYIMAGE () / 2; + + if (nb == 0 && nbHili > 0) + { + if (nbHili == 1) + BlupiSound (m_rankBlupiHili, table_sound_boing[Random (0, 2)], avg, true); + else + m_pSound->PlayImage (table_sound_boing[Random (0, 2)], avg); + } + + if (nb > 0) + { + if (nbHili == 1) + BlupiSound (m_rankBlupiHili, table_sound_go[Random (0, 5)], avg, true); + else + m_pSound->PlayImage (table_sound_gom[Random (0, 2)], avg); + } +} + +// Indique si une cellule est occupée pour un tracks. +// La cellule est considérée libre uniquement si elle +// contient un blupi à pied ou un détonnateur de mine +// (personnage invisible). + +bool +CDecor::IsTracksHere (Point cel, bool bSkipInMove) +{ + Sint32 rank; + + if (!IsValid (cel)) + return false; + + for (rank = 0; rank < MAXBLUPI; rank++) + { + if ( + m_blupi[rank].bExist && + (m_blupi[rank].perso != 0 || // blupi ? + m_blupi[rank].vehicule != 0 || // à pied ? + m_bInvincible) && + m_blupi[rank].perso != 6) // détonnateur ? + { + if (bSkipInMove && m_blupi[rank].goalCel.x != -1) + continue; + + if (cel.x == m_blupi[rank].cel.x && cel.y == m_blupi[rank].cel.y) + { + m_blupiHere = rank; + return true; + } + + if (cel.x == m_blupi[rank].destCel.x && cel.y == m_blupi[rank].destCel.y) + { + m_blupiHere = rank; + return true; + } + } + } + + return false; +} + +// Indique si une cellule est occupée par un blupi. +// Le blupi donné dans exRank est ignoré ! + +bool +CDecor::IsBlupiHereEx (Point cel1, Point cel2, Sint32 exRank, bool bSkipInMove) +{ + Sint32 rank; + + if (!IsValid (cel1)) + return false; + if (!IsValid (cel2)) + return false; + + for (rank = 0; rank < MAXBLUPI; rank++) + { + if ( + m_blupi[rank].bExist && + m_blupi[rank].perso != 6 && // pas le détonnateur de mine + rank != exRank) + { + if (bSkipInMove && m_blupi[rank].goalCel.x != -1) + continue; + + if ( + cel1.x <= m_blupi[rank].cel.x && cel2.x >= m_blupi[rank].cel.x && + cel1.y <= m_blupi[rank].cel.y && cel2.y >= m_blupi[rank].cel.y) + { + m_blupiHere = rank; + return true; + } + + if ( + cel1.x <= m_blupi[rank].destCel.x && + cel2.x >= m_blupi[rank].destCel.x && + cel1.y <= m_blupi[rank].destCel.y && cel2.y >= m_blupi[rank].destCel.y) + { + m_blupiHere = rank; + return true; + } + } + } + + return false; +} + +// Indique si une cellule est occupée par un blupi. +// Le blupi donné dans exRank est ignoré ! + +bool +CDecor::IsBlupiHereEx (Point cel, Sint32 exRank, bool bSkipInMove) +{ + Sint32 rank; + + if (!IsValid (cel)) + return false; + + for (rank = 0; rank < MAXBLUPI; rank++) + { + if ( + m_blupi[rank].bExist && + m_blupi[rank].perso != 6 && // pas le détonnateur de mine + rank != exRank) + { + if (bSkipInMove && m_blupi[rank].goalCel.x != -1) + continue; + + if (cel.x == m_blupi[rank].cel.x && cel.y == m_blupi[rank].cel.y) + { + m_blupiHere = rank; + return true; + } + + if (cel.x == m_blupi[rank].destCel.x && cel.y == m_blupi[rank].destCel.y) + { + m_blupiHere = rank; + return true; + } + } + } + + return false; +} + +// Indique si une cellule est occupée par un blupi. + +bool +CDecor::IsBlupiHere (Point cel, bool bSkipInMove) +{ + return IsBlupiHereEx (cel, -1, bSkipInMove); +} + +// Indique si une cellule future (dans une direction donnée) +// est déjà occupée par un blupi. + +bool +CDecor::IsBlupiHere (Point cel, Sint32 direct, bool bSkipInMove) +{ + Point vector; + + vector = GetVector (direct); + + cel.x += vector.x; + cel.y += vector.y; + + return IsBlupiHereEx (cel, -1, bSkipInMove); +} + +// Retourne les niveaux des jauges. + +void +CDecor::GetLevelJauge (Sint32 * pLevels, Sint32 * pTypes) +{ + Sint32 rank; + + pLevels[0] = -1; + pLevels[1] = -1; + + rank = m_rankBlupiHili; + + if (m_nbBlupiHili == 1) // un seul blupi sélectionné ? + { + pLevels[0] = (m_blupi[rank].energy * 100) / MAXENERGY; + + pTypes[0] = 1; // rouge + if (m_blupi[rank].energy > MAXENERGY / 4) + { + pTypes[0] = 2; // bleu + } + } + + if (m_blupi[rank].interrupt == 0 && m_blupi[rank].jaugeMax > 0) + { + pLevels[1] = (m_blupi[rank].jaugePhase * 100) / m_blupi[rank].jaugeMax; + pTypes[1] = 3; // jaune + } +} + +// Retourne true si un blupi est déjà sélectionné et qu'il +// effectue une action prioritaire. Dans ce cas, il faut tout +// de suite mettre le menu "stoppe" s'il est cliqué. + +bool +CDecor::IsWorkBlupi (Sint32 rank) +{ + if ( + m_blupi[rank].bHili && m_blupi[m_rankBlupiHili].goalAction != 0 && + m_blupi[m_rankBlupiHili].interrupt <= 0) + return true; + + return false; +} + +// Retourne les boutons possibles à un endroit donné, +// pour le blupi sélectionné. + +void +CDecor::BlupiGetButtons ( + Point pos, Sint32 & nb, Buttons * pButtons, Errors * pErrors, + std::unordered_map & texts, Sint32 & perso) +{ + Buttons * pB = pButtons; + Errors * pE = pErrors; + Point cel, cel2; + Sint32 i, rank, channel, icon; + Errors error; + Buttons button; + bool bBuild = false; + bool bPut; + const char * textForButton; + + static struct { + Buttons button; + Sint32 icon; + } table_buttons[] = { + // + {BUTTON_GO, 0}, // + {BUTTON_DJEEP, 0}, // + {BUTTON_DARMOR, 0}, // + {BUTTON_EAT, 0}, // + {BUTTON_BOIT, 0}, // + {BUTTON_CARRY, 0}, // + {BUTTON_DEPOSE, 0}, // + {BUTTON_LABO, 0}, // + {BUTTON_ABAT, 0}, // + {BUTTON_ABATn, 0}, // + {BUTTON_ROC, 0}, // + {BUTTON_ROCn, 0}, // + {BUTTON_CULTIVE, 0}, // + {BUTTON_FLOWER, 0}, // + {BUTTON_FLOWERn, 0}, // + {BUTTON_DYNAMITE, 0}, // + {BUTTON_FLAG, 0}, // + {BUTTON_EXTRAIT, 0}, // + {BUTTON_FABJEEP, 0}, // + {BUTTON_FABMINE, 0}, // + {BUTTON_FABDISC, 0}, // + {BUTTON_MAKEARMOR, 0}, // + {BUTTON_BUILD1, 36}, // si planches (cabane) + {BUTTON_BUILD2, 36}, // si planches (nurserie) + {BUTTON_BUILD4, 36}, // si planches (mine) + {BUTTON_PALIS, 36}, // si planches + {BUTTON_BRIDGE, 36}, // si planches + {BUTTON_BOAT, 36}, // si planches + {BUTTON_BUILD6, 36}, // si planches (téléporteur) + {BUTTON_BUILD3, 44}, // si pierres (laboratoire) + {BUTTON_BUILD5, 44}, // si pierres (usine) + {BUTTON_WALL, 44}, // si pierres + {BUTTON_TOWER, 44}, // si pierres + {BUTTON_STOP, 0}, // + {BUTTON_NONE, 0} // + }; + + nb = 0; + perso = 0; + + cel = ConvPosToCel (pos); + cel2 = ConvPosToCel2 (pos); + + if (m_nbBlupiHili == 0) + return; + + if (m_nbBlupiHili > 1) // sélection multiple ? + { + error = CelOkForAction (cel, table_actions[BUTTON_GO], m_rankBlupiHili); + if (error == 0) + { + *pB++ = BUTTON_GO; + *pE++ = Errors::NONE; + nb++; + } + + for (rank = 0; rank < MAXBLUPI; rank++) + { + if (m_blupi[rank].bExist && m_blupi[rank].goalAction != 0) + { + *pB++ = BUTTON_STOP; + *pE++ = Errors::NONE; + nb++; + break; + } + } + + return; + } + + if (m_nbBlupiHili != 1) + return; + + perso = m_blupi[m_rankBlupiHili].perso; + + // Si action prioritaire en cours -> seulement stoppe. + if ( + m_blupi[m_rankBlupiHili].goalAction != 0 && + m_blupi[m_rankBlupiHili].interrupt <= 0) + { + if ( + abs (m_blupi[m_rankBlupiHili].cel.x - cel.x) <= 3 && + abs (m_blupi[m_rankBlupiHili].cel.y - cel.y) <= 3 && + CelOkForAction (cel, table_actions[BUTTON_STOP], m_rankBlupiHili) == 0) + { + *pB++ = BUTTON_STOP; + *pE++ = Errors::NONE; + nb++; + } + return; + } + + // Vérifie si le blupi sélectionné peut construire. + if (m_rankBlupiHili >= 0) + { + if ( + m_blupi[m_rankBlupiHili].energy > MAXENERGY / 4 && + m_blupi[m_rankBlupiHili].takeChannel == -1 && + m_blupi[m_rankBlupiHili].vehicule == 0) // à pied ? + bBuild = true; + } + + // Met les différentes actions. + for (size_t i = 0; i < countof (table_buttons); ++i) + { + button = table_buttons[i].button; + + if (m_buttonExist[button] == 0) + continue; + + error = CelOkForAction (cel, table_actions[button], m_rankBlupiHili); + + if (error == 0) + bPut = true; + else + bPut = false; + + if ( + bBuild && table_buttons[i].icon != 0 && // toujours présent si matière ? + (m_rankBlupiHili < 0 || + m_blupi[m_rankBlupiHili].perso != 8 || // pas disciple ? + table_buttons[i].icon != 44)) // ni pierres ? + { + GetObject (cel2, channel, icon); + if ( + channel == CHOBJECT && icon == table_buttons[i].icon && // matière ? + cel.x % 2 == 1 && cel.y % 2 == 1) + { + bPut = true; // bouton présent, mais disable ! + } + } + + if (bPut) + { + *pB++ = button; + *pE++ = error; + nb++; + } + } + + // Si le premier bouton est "abat", ajoute "va" devant ! + if (pButtons[0] == BUTTON_ABAT) + { + for (i = nb; i > 0; i--) + { + pButtons[i] = pButtons[i - 1]; + pErrors[i] = pErrors[i - 1]; + } + + pButtons[0] = BUTTON_GO; + pErrors[0] = Errors::MISC; + nb++; + } + + // Regarde s'il faut ajouter le bouton "répète". + if ( + m_blupi[m_rankBlupiHili].repeatLevel != -1 || + m_blupi[m_rankBlupiHili].energy <= MAXENERGY / 4 || + m_buttonExist[BUTTON_REPEAT] == 0) + return; + + for (i = 0; i < nb; i++) + { + rank = ListSearch (m_rankBlupiHili, pButtons[i], cel, textForButton); + if (rank > 0) // au moins 2 actions à répéter ? + { + m_blupi[m_rankBlupiHili].repeatLevelHope = rank; + + pButtons[nb] = BUTTON_REPEAT; + pErrors[nb] = Errors::REPEAT; + texts[nb] = textForButton; + nb++; + return; + } + } +} + +// Initialise les conditions de fin. + +void +CDecor::TerminatedInit () +{ + m_winCount = 50; + + m_winLastHachBlupi = 0; + m_winLastHachPlanche = 0; + m_winLastHachTomate = 0; + m_winLastHachMetal = 0; + m_winLastHachRobot = 0; + m_winLastHome = 0; + m_winLastHomeBlupi = 0; + m_winLastRobots = 0; +} + +// Vérifie si la partie est terminée. +// Retourne 0 si la partie n'est pas terminée. +// Retourne 1 si la partie est perdue. +// Retourne 2 si la partie est gagnée. + +Sint32 +CDecor::IsTerminated () +{ + Sint32 nb, count, out; + Point pos; + + pos.x = LXIMAGE () / 2; + pos.y = LYIMAGE () / 2; + + count = m_winCount; + m_winCount = 50; + + if (m_winLastHome > m_nbStatHome) // une maison en moins ? + { + out = 1; // perdu + goto delay; + } + m_winLastHome = m_nbStatHome; + + nb = StatisticGetBlupi (); + if (nb < m_term.nbMinBlupi) + { + out = 1; // perdu + goto delay; + } + if (nb < m_term.nbMaxBlupi) + return 0; // continue + + if (m_term.bStopFire) + { + nb = StatisticGetFire (); + if (nb > 0) + return 0; // continue; + } + + if (m_term.bHachBlupi) + { + if (m_winLastHachBlupi < m_nbStatHachBlupi) + m_pSound->PlayImage (SOUND_GOAL, pos); + m_winLastHachBlupi = m_nbStatHachBlupi; + + if (m_nbStatHachBlupi < m_nbStatHach * m_term.nbMinBlupi) + return 0; // continue; + } + + if (m_term.bHachPlanche) + { + if (m_winLastHachPlanche < m_nbStatHachPlanche) + m_pSound->PlayImage (SOUND_GOAL, pos); + m_winLastHachPlanche = m_nbStatHachPlanche; + + if (m_nbStatHachPlanche < m_nbStatHach) + return 0; // continue; + } + + if (m_term.bHachTomate) + { + if (m_winLastHachTomate < m_nbStatHachTomate) + m_pSound->PlayImage (SOUND_GOAL, pos); + m_winLastHachTomate = m_nbStatHachTomate; + + if (m_nbStatHachTomate < m_nbStatHach) + return 0; // continue; + } + + if (m_term.bHachMetal) + { + if (m_winLastHachMetal < m_nbStatHachMetal) + m_pSound->PlayImage (SOUND_GOAL, pos); + m_winLastHachMetal = m_nbStatHachMetal; + + if (m_nbStatHachMetal < m_nbStatHach) + return 0; // continue; + } + + if (m_term.bHachRobot) + { + if (m_winLastRobots > m_nbStatRobots) + { + out = 1; // perdu + goto delay; + } + m_winLastRobots = m_nbStatRobots; + + if (m_winLastHachRobot < m_nbStatHachRobot) + m_pSound->PlayImage (SOUND_GOAL, pos); + m_winLastHachRobot = m_nbStatHachRobot; + + if (m_nbStatHachRobot < m_nbStatHach) + return 0; // continue; + } + + if (m_term.bHomeBlupi) + { + if (m_winLastHomeBlupi < m_nbStatHomeBlupi) + m_pSound->PlayImage (SOUND_GOAL, pos); + m_winLastHomeBlupi = m_nbStatHomeBlupi; + + if (m_nbStatHomeBlupi < m_nbStatHome) + return 0; // continue; + } + + if (m_term.bKillRobots) + { + if (m_winLastRobots > m_nbStatRobots) + m_pSound->PlayImage (SOUND_GOAL, pos); + m_winLastRobots = m_nbStatRobots; + + if (m_nbStatRobots > 0) + return 0; // continue; + } + + out = 2; // gagné + +delay: + m_winCount = count; + if (m_winCount == 0) + return out; // perdu/gagné + + m_winCount--; + return 0; // continue +} + +// Retourne la structure pour terminer une partie. + +Term * +CDecor::GetTerminated () +{ + return &m_term; +} diff --git a/src/decgoal.cxx b/src/decgoal.cxx new file mode 100644 index 0000000..1f39427 --- /dev/null +++ b/src/decgoal.cxx @@ -0,0 +1,3569 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "decgoal.h" +#include "decor.h" +#include "def.h" + +// clang-format off +Sint16 table_goal_nbop[] = +{ + 0, // term + 3, // gohili + 3, // gohili2 + 3, // goblupi + 4, // putfloor + 4, // putobject + 9, // buildfloor + 9, // buildobject + 2, // action + 1, // interrupt + 1, // energy + 3, // addmoves + 6, // other + 0, // finishmove + 2, // take + 0, // depose + 1, // group + 2, // work + 4, // testobject + 2, // fix + 6, // otherfix + 3, // addicons + 2, // newblupi + 1, // sound + 1, // repeat + 1, // otherloop + 0, // nextloop + 2, // arrangeobject + 0, // labo + 2, // cache + 0, // delete + 3, // electro + 3, // newperso + 2, // usinebuild + 2, // usinefree + 2, // explose1 + 2, // explose2 + 1, // vehicule + 4, // takeobject + 3, // floorjump + 2, // adddrapeau + 2, // amorce + 1, // malade + 2, // ifterm + 2, // ifdebarque + 0, // isnomalade + 2, // skipskill + 2, // teleporte + 0, // actualise + 2, // waitfree +}; + +// Va, mon petit. +static Sint16 table_goal_go[] = +{ + EV_ACTION_GO, + GOAL_GOHILI, 0, 0, false, + GOAL_TERM, + 0 +}; + +// Blupi va dans sa maison. +static Sint16 table_goal_maison[] = +{ + EV_ACTION_HOUSE, + GOAL_GOHILI2, +1, +1, false, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_HAPPY, DIRECT_E, + GOAL_TERM, + 0 +}; + +// Blupi bucheron. +static Sint16 table_goal_abat1[] = +{ + EV_ACTION_ABAT1, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, true, + //? GOAL_ENERGY, MAXENERGY/4, + GOAL_GROUP, 4, + GOAL_TESTOBJECT, 0, -1, CHOBJECT, 6, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 30, -1, -1, DIMOBJY + 20, 1, -1 * 100, + + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, 0, -1, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, 0, 0, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, -1, 0, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_BUILDOBJECT, -1, 0, CHOBJECT, 36, -1, -1, 80 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_S, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_OTHER, CHOBJECT, 6, 11, -1, -1, EV_ACTION_ABAT1, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_abat2[] = +{ + EV_ACTION_ABAT2, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, true, + //? GOAL_ENERGY, MAXENERGY/4, + GOAL_GROUP, 4, + GOAL_TESTOBJECT, 0, -1, CHOBJECT, 7, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 31, -1, -1, DIMOBJY + 20, 1, -1 * 100, + + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, 0, -1, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, 0, 0, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, -1, 0, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_BUILDOBJECT, -1, 0, CHOBJECT, 36, -1, -1, 80 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_S, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_OTHER, CHOBJECT, 6, 11, -1, -1, EV_ACTION_ABAT1, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_abat3[] = +{ + EV_ACTION_ABAT3, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, 0, true, + //? GOAL_ENERGY, MAXENERGY/4, + GOAL_GROUP, 4, + GOAL_TESTOBJECT, -1, 0, CHOBJECT, 8, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, 0, + GOAL_BUILDOBJECT, -1, 0, CHOBJECT, 32, -1, -1, DIMOBJY + 20, 1, -1 * 100, + + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, -1, 0, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, -1, -1, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, -1, 0, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_BUILDOBJECT, -1, 0, CHOBJECT, 36, -1, -1, 80 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_S, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_OTHER, CHOBJECT, 6, 11, -1, -1, EV_ACTION_ABAT1, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_abat4[] = +{ + EV_ACTION_ABAT4, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, 0, true, + //? GOAL_ENERGY, MAXENERGY/4, + GOAL_GROUP, 4, + GOAL_TESTOBJECT, 0, 0, CHOBJECT, 9, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, 0, + GOAL_BUILDOBJECT, 0, 0, CHOBJECT, 33, -1, -1, DIMOBJY, 1, -1 * 100, + + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, 0, 0, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, 0, 0, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, 0, 0, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_BUILDOBJECT, 0, 0, CHOBJECT, 36, -1, -1, 80 / 10, 10, -10 * 100, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_S, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_OTHER, CHOBJECT, 6, 11, -1, -1, EV_ACTION_ABAT1, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_abat5[] = +{ + EV_ACTION_ABAT5, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, 0, true, + //? GOAL_ENERGY, MAXENERGY/4, + GOAL_GROUP, 4, + GOAL_TESTOBJECT, 0, 0, CHOBJECT, 10, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, 0, + GOAL_BUILDOBJECT, 0, 0, CHOBJECT, 34, -1, -1, DIMOBJY, 1, -1 * 100, + + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, 0, 0, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, 0, 0, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, 0, 0, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_BUILDOBJECT, 0, 0, CHOBJECT, 36, -1, -1, 80 / 10, 10, -10 * 100, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_S, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_OTHER, CHOBJECT, 6, 11, -1, -1, EV_ACTION_ABAT1, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_abat6[] = +{ + EV_ACTION_ABAT6, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, 0, true, + //? GOAL_ENERGY, MAXENERGY/4, + GOAL_GROUP, 4, + GOAL_TESTOBJECT, 0, 0, CHOBJECT, 11, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, 0, + GOAL_BUILDOBJECT, 0, 0, CHOBJECT, 35, -1, -1, DIMOBJY, 1, -1 * 100, + + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, 0, 0, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, 0, 0, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ADDMOVES, 0, 0, 1, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + + GOAL_BUILDOBJECT, 0, 0, CHOBJECT, 36, -1, -1, 80 / 10, 10, -10 * 100, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_S, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_OTHER, CHOBJECT, 6, 11, -1, -1, EV_ACTION_ABAT1, + GOAL_TERM, + 0 +}; + +// Blupi tailleur de pierre. +static Sint16 table_goal_roc1[] = +{ + EV_ACTION_ROC1, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, +1, true, + //? GOAL_ENERGY, MAXENERGY/4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 38, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 39, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 40, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 41, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 42, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 43, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 44, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_OTHER, CHOBJECT, 37, 43, -1, -1, EV_ACTION_ROC1, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_roc2[] = +{ + EV_ACTION_ROC2, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, +1, true, + //? GOAL_ENERGY, MAXENERGY/4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 39, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 40, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 41, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 42, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 43, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 44, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_OTHER, CHOBJECT, 37, 43, -1, -1, EV_ACTION_ROC1, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_roc3[] = +{ + EV_ACTION_ROC3, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, +1, true, + //? GOAL_ENERGY, MAXENERGY/4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 40, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 41, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 42, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 43, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 44, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_OTHER, CHOBJECT, 37, 43, -1, -1, EV_ACTION_ROC1, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_roc4[] = +{ + EV_ACTION_ROC4, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, +1, true, + //? GOAL_ENERGY, MAXENERGY/4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 41, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 42, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 43, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 44, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_OTHER, CHOBJECT, 37, 43, -1, -1, EV_ACTION_ROC1, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_roc5[] = +{ + EV_ACTION_ROC5, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, +1, true, + //? GOAL_ENERGY, MAXENERGY/4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 42, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 43, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 44, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_OTHER, CHOBJECT, 37, 43, -1, -1, EV_ACTION_ROC1, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_roc6[] = +{ + EV_ACTION_ROC6, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, +1, true, + //? GOAL_ENERGY, MAXENERGY/4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 43, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 44, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_OTHER, CHOBJECT, 37, 43, -1, -1, EV_ACTION_ROC1, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_roc7[] = +{ + EV_ACTION_ROC7, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, +1, true, + //? GOAL_ENERGY, MAXENERGY/4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 44, -1, -1, 120 / 10, 10, -10 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + + GOAL_FINISHMOVE, + GOAL_OTHER, CHOBJECT, 37, 43, -1, -1, EV_ACTION_ROC1, + GOAL_TERM, + 0 +}; + +// Construction d'une cabane. +static Sint16 table_goal_build1[] = +{ + EV_ACTION_BUILD1, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_BUILDFLOOR, 0, -1, CHFLOOR, 16, CHMASK1, 0, 16, 14, 1 * 100, // briques + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, +1, -1, true, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + //? GOAL_ENERGY, MAXENERGY/4, + // échaffaudage + GOAL_BUILDOBJECT, -1, 0, CHOBJECT, 62, -1, -1, DIMOBJY / 10, 18, 10 * 100, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_BUILDSEC, DIRECT_S, + GOAL_GOBLUPI, +1, +1, true, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_BUILDSOURD, DIRECT_W, + GOAL_GOBLUPI, 0, -2, true, + GOAL_GOBLUPI, -2, 0, true, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_GOBLUPI, +2, 0, true, + GOAL_GOBLUPI, 0, +1, true, + // maison + GOAL_BUILDOBJECT, -2, 0, CHOBJECT, 61, -1, -1, DIMOBJY / 10, 20, 10 * 100, + GOAL_ACTION, ACTION_BUILDSOURD, DIRECT_W, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_BUILDSOURD, DIRECT_W, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_BUILDSOURD, DIRECT_W, + GOAL_GOBLUPI, 0, -1, true, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_BUILDSEC, DIRECT_S, + GOAL_GOBLUPI, +1, 0, true, + GOAL_GOBLUPI, 0, +1, true, + GOAL_FINISHMOVE, + GOAL_TERM, + 0 +}; + +// Construction d'une nurserie. +static Sint16 table_goal_build2[] = +{ + EV_ACTION_BUILD2, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_BUILDFLOOR, 0, -1, CHFLOOR, 52, CHMASK1, 0, 16, 14, 1 * 100, // nurserie + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, +1, -1, true, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_PUTOBJECT, -1, 0, -1, -1, // enlève les planches + GOAL_GOBLUPI, -1, +1, true, + GOAL_ACTION, ACTION_BUILDSEC, DIRECT_S, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_BUILDSEC, DIRECT_S, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_BUILDSEC, DIRECT_S, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_BUILDSEC, DIRECT_S, + GOAL_GOBLUPI, +1, +1, true, + GOAL_FINISHMOVE, + GOAL_TERM, + 0 +}; + +// Construction d'un laboratoire. +static Sint16 table_goal_build3[] = +{ + EV_ACTION_BUILD3, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_BUILDFLOOR, 0, -1, CHFLOOR, 16, CHMASK1, 0, 16, 14, 1 * 100, // briques + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, +1, -1, true, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_GOBLUPI, +1, 0, true, + // laboratoire + GOAL_BUILDOBJECT, -1, 0, CHOBJECT, 28, -1, -1, DIMOBJY / 10, 20, 10 * 100, + GOAL_ACTION, ACTION_BUILDSEC, DIRECT_S, + GOAL_GOBLUPI, +1, 0, true, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_BUILDSOURD, DIRECT_W, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_BUILDSOURD, DIRECT_W, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_BUILDSOURD, DIRECT_W, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_FINISHMOVE, + GOAL_TERM, + 0 +}; + +// Construction d'une mine. +static Sint16 table_goal_build4[] = +{ + EV_ACTION_BUILD4, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 2, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + // échaffaudage + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 126, -1, -1, DIMOBJY / 10, 18, 10 * 100, + GOAL_ACTION, ACTION_BUILDSEC, DIRECT_S, + GOAL_GOBLUPI, +1, -1, true, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_GOBLUPI, +1, 0, true, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_BUILDSOURD, DIRECT_W, + GOAL_GOBLUPI, 0, -2, true, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_GOBLUPI, +1, 0, true, + GOAL_GOBLUPI, 0, +1, true, + // mine + GOAL_BUILDOBJECT, -2, 0, CHOBJECT, 122, -1, -1, DIMOBJY / 10, 20, 10 * 100, + GOAL_ACTION, ACTION_BUILDSOURD, DIRECT_W, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_BUILDSOURD, DIRECT_W, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_BUILDSOURD, DIRECT_W, + GOAL_GOBLUPI, 0, -1, true, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_BUILDSEC, DIRECT_S, + GOAL_GOBLUPI, +1, 0, true, + GOAL_GOBLUPI, 0, +1, true, + GOAL_FINISHMOVE, + GOAL_TERM, + 0 +}; + +// Construction d'une usine. +static Sint16 table_goal_build5[] = +{ + EV_ACTION_BUILD5, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_BUILDFLOOR, 0, -1, CHFLOOR, 16, CHMASK1, 0, 16, 14, 1 * 100, // briques + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, +1, -1, true, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_GOBLUPI, +1, 0, true, + // usine + GOAL_BUILDOBJECT, -1, 0, CHOBJECT, 120, -1, -1, DIMOBJY / 10, 20, 10 * 100, + GOAL_ACTION, ACTION_BUILDSEC, DIRECT_S, + GOAL_GOBLUPI, +1, 0, true, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_BUILDSOURD, DIRECT_W, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_BUILDSOURD, DIRECT_W, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_BUILDSOURD, DIRECT_W, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_FINISHMOVE, + GOAL_TERM, + 0 +}; + +// Construction d'un téléporteur. +static Sint16 table_goal_build6[] = +{ + EV_ACTION_BUILD6, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_BUILDFLOOR, 0, -1, CHFLOOR, 80, CHMASK1, 0, 16, 14, 1 * 100, // téléporteur + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, +1, -1, true, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_PUTOBJECT, -1, 0, -1, -1, // enlève les planches + GOAL_GOBLUPI, -1, +1, true, + GOAL_ACTION, ACTION_BUILDSEC, DIRECT_S, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_BUILDSEC, DIRECT_S, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_BUILDSEC, DIRECT_S, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_BUILDSEC, DIRECT_S, + GOAL_GOBLUPI, +1, +1, true, + GOAL_FINISHMOVE, + GOAL_GOBLUPI, 0, -2, true, + GOAL_ACTION, ACTION_STOP, DIRECT_S, + GOAL_TERM, + 0 +}; + +// Construction d'un mur. +static Sint16 table_goal_mur[] = +{ + EV_ACTION_WALL, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 26, -1, -1, DIMOBJY / 5, 40, 5 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_PUTOBJECT, 0, 0, -1, -1, // enlève les pierres + GOAL_GOBLUPI, +1, +1, true, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_S, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_W, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_W, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_S, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_W, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_W, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_TCHAO, DIRECT_E, + GOAL_FINISHMOVE, + GOAL_TERM, + 0 +}; + +// Construction d'une tour. +static Sint16 table_goal_tour[] = +{ + EV_ACTION_TOWER, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 27, -1, -1, DIMOBJY / 4, 20, 4 * 100, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_GOBLUPI, +1, -1, true, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_PUTOBJECT, -1, 0, -1, -1, // enlève les pierres + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_W, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_W, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_W, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_W, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_W, + GOAL_ACTION, ACTION_PIOCHEPIERRE, DIRECT_E, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_W, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_W, + GOAL_ACTION, ACTION_BUILDBREF, DIRECT_W, + GOAL_ACTION, ACTION_STOP, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_ARRANGEOBJECT, -1, -1, + GOAL_ACTION, ACTION_TCHAO, DIRECT_E, + GOAL_TERM, + 0 +}; + +// Construction d'une palissade. +static Sint16 table_goal_palis[] = +{ + EV_ACTION_PALIS, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 71, -1, -1, DIMOBJY / 10, 20, 10 * 100, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_PICKAXE, DIRECT_E, + GOAL_PUTOBJECT, 0, 0, -1, -1, // enlève les planches + GOAL_GOBLUPI, +1, +1, true, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + GOAL_FINISHMOVE, + GOAL_TERM, + 0 +}; + +// Transporte (est). +static Sint16 table_goal_carry[] = +{ + EV_ACTION_CARRY, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 4, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_BUILDOBJECT, 0, -1, -2, -2, -1, -1, 9 + 18, 1, 1 * 100, + GOAL_ADDMOVES, 0, -1, 2, + GOAL_ACTION, ACTION_CARRY, DIRECT_E, + GOAL_TAKE, 0, -1, + GOAL_TERM, + 0 +}; + +// Transporte (sud). +static Sint16 table_goal_carry2[] = +{ + EV_ACTION_CARRY2, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, 0, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_ACTION, ACTION_STOP, DIRECT_S, + GOAL_GROUP, 4, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, 0, + GOAL_BUILDOBJECT, -1, 0, -2, -2, -1, -1, 9 + 18, 1, 1 * 100, + GOAL_ADDMOVES, -1, 0, 3, + GOAL_ACTION, ACTION_CARRY, DIRECT_S, + GOAL_TAKE, -1, 0, + GOAL_TERM, + 0 +}; + +// Repose (est). +static Sint16 table_goal_depose[] = +{ + EV_ACTION_DROP, + GOAL_GOHILI2, 0, +1, false, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 6, + GOAL_IFTERM, +1, 0, // emplacement libre ? + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_PUTOBJECT, 0, -1, -3, -3, // l'objet transporté + GOAL_BUILDOBJECT, 0, -1, -2, -2, -1, -1, 11, 1, 1 * 100, + GOAL_ADDMOVES, 0, -1, 4, + GOAL_DEPOSE, + GOAL_ACTION, ACTION_DROP, DIRECT_E, + GOAL_FINISHMOVE, + GOAL_TERM, + 0 +}; + +// Repose (sud). +static Sint16 table_goal_depose2[] = +{ + EV_ACTION_DROP2, + GOAL_GOHILI2, +1, 0, false, + GOAL_ACTION, ACTION_STOP, DIRECT_S, + GOAL_GROUP, 6, + GOAL_IFTERM, 0, +1, // emplacement libre ? + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, 0, + GOAL_PUTOBJECT, -1, 0, -3, -3, // l'objet transporté + GOAL_BUILDOBJECT, -1, 0, -2, -2, -1, -1, 11, 1, 1 * 100, + GOAL_ADDMOVES, -1, 0, 5, + GOAL_DEPOSE, + GOAL_ACTION, ACTION_DROP, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_TERM, + 0 +}; + +// Repose des oeufs sur la nurserie. +static Sint16 table_goal_newblupi[] = +{ + EV_ACTION_NEWBLUPI, + GOAL_GOHILI2, 0, +1, false, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 5, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_PUTOBJECT, 0, -1, -3, -3, // l'objet transporté + GOAL_BUILDOBJECT, 0, -1, -2, -2, -1, -1, 11, 1, 1 * 100, + GOAL_ADDMOVES, 0, -1, 4, + GOAL_DEPOSE, + GOAL_ACTION, ACTION_DROP, DIRECT_E, + GOAL_FINISHMOVE, + GOAL_GOBLUPI, -1, 0, true, + GOAL_GROUP, 3, + GOAL_PUTOBJECT, +1, -1, CHOBJECT, 64, // 4 oeufs + GOAL_BUILDFLOOR, +1, -1, CHFLOOR, -1, -1, -1, 100, 1, 1 * 100, + GOAL_ADDICONS, +1, -1, 3, + GOAL_GOBLUPI, 0, -1, true, + GOAL_GOBLUPI, 0, +1, true, + GOAL_GOBLUPI, 0, -1, true, + GOAL_GOBLUPI, 0, +1, true, + GOAL_GOBLUPI, 0, -1, true, + GOAL_GOBLUPI, 0, +1, true, + GOAL_GOBLUPI, 0, -1, true, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_FINISHMOVE, + GOAL_NEWBLUPI, +1, -1, + GOAL_GOBLUPI, 0, -1, true, + GOAL_GOBLUPI, 0, +1, true, + GOAL_TERM, + 0 +}; + +// Cultive des tomates. +static Sint16 table_goal_cultive[] = +{ + EV_ACTION_CULTIVE, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +2, 0, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_FIX, -2, 0, + GOAL_REPEAT, true, + GOAL_OTHERFIX, CHFLOOR, 1, 1, 19, 32, EV_ACTION_CULTIVE2, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_cultive2[] = +{ + EV_ACTION_CULTIVE2, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_BUILDFLOOR, -1, -1, CHFLOOR, 57, CHMASK1, 0, 16, 6, 1 * 100, // terre + GOAL_ACTION, ACTION_BECHE, DIRECT_E, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_BECHE, DIRECT_E, + GOAL_FINISHMOVE, + + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 57, -1, -1, DIMOBJY, 1, 1 * 100, + GOAL_ACTION, ACTION_ARROSE, DIRECT_E, + GOAL_ACTION, ACTION_ARROSE, DIRECT_E, + GOAL_FINISHMOVE, + + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 58, -1, -1, DIMOBJY, 1, 1 * 100, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_ARROSE, DIRECT_E, + GOAL_ACTION, ACTION_ARROSE, DIRECT_E, + GOAL_FINISHMOVE, + + GOAL_BUILDOBJECT, 0, 0, CHOBJECT, 59, -1, -1, DIMOBJY, 1, 1 * 100, + GOAL_ACTION, ACTION_BECHE, DIRECT_E, + GOAL_ACTION, ACTION_BECHE, DIRECT_E, + GOAL_GOBLUPI, 0, +1, true, + GOAL_FINISHMOVE, + + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 60, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ACTION, ACTION_ARROSE, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_ARROSE, DIRECT_E, + GOAL_GOBLUPI, 0, +1, true, + GOAL_FINISHMOVE, + + GOAL_BUILDFLOOR, 0, -1, CHFLOOR, 1, CHMASK1, 0, 16, 1, 1 * 100, // herbe + GOAL_FINISHMOVE, + + GOAL_OTHERFIX, CHFLOOR, 1, 1, 19, 32, EV_ACTION_CULTIVE2, + GOAL_TERM, + 0 +}; + +// Bouffe des tomates (est). +static Sint16 table_goal_mange[] = +{ + EV_ACTION_EAT, + GOAL_GOHILI2, 0, +1, false, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 4, + GOAL_TESTOBJECT, 0, -1, CHOBJECT, 60, // tomates ? + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_BUILDOBJECT, 0, -1, -1, -1, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ACTION, ACTION_EAT, DIRECT_E, + GOAL_ACTION, ACTION_EAT, DIRECT_E, + GOAL_ACTION, ACTION_EAT, DIRECT_E, + + GOAL_GROUP, 2, + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, 0, -1, -1, -1, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_TERM, + 0 +}; + +// Bouffe des tomates (sud). +static Sint16 table_goal_mange2[] = +{ + EV_ACTION_EAT2, + GOAL_GOHILI2, +1, 0, false, + GOAL_ACTION, ACTION_STOP, DIRECT_S, + GOAL_GROUP, 4, + GOAL_TESTOBJECT, -1, 0, CHOBJECT, 60, // tomates ? + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, 0, + GOAL_BUILDOBJECT, -1, 0, -1, -1, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ACTION, ACTION_EAT, DIRECT_E, + GOAL_ACTION, ACTION_EAT, DIRECT_E, + GOAL_ACTION, ACTION_EAT, DIRECT_E, + + GOAL_GROUP, 2, + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, -1, 0, -1, -1, + GOAL_ACTION, ACTION_STOP, DIRECT_S, + GOAL_TERM, + 0 +}; + +// Boit à la bouteille (est). +static Sint16 table_goal_boit[] = +{ + EV_ACTION_DRINK, + GOAL_GOHILI2, 0, +1, false, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 5, + GOAL_TESTOBJECT, 0, -1, CHOBJECT, 80, // bouteille ? + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_PUTOBJECT, 0, -1, -1, -1, + GOAL_ACTION, ACTION_DRINK, DIRECT_E, + GOAL_ACTION, ACTION_DRINK, DIRECT_E, + GOAL_ACTION, ACTION_DRINK, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_TERM, + 0 +}; + +// Boit à la bouteille (sud). +static Sint16 table_goal_boit2[] = +{ + EV_ACTION_DRINK2, + GOAL_GOHILI2, +1, 0, false, + GOAL_ACTION, ACTION_STOP, DIRECT_S, + GOAL_GROUP, 5, + GOAL_TESTOBJECT, -1, 0, CHOBJECT, 80, // bouteille ? + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, 0, + GOAL_PUTOBJECT, -1, 0, -1, -1, + GOAL_ACTION, ACTION_DRINK, DIRECT_E, + GOAL_ACTION, ACTION_DRINK, DIRECT_E, + GOAL_ACTION, ACTION_DRINK, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_S, + GOAL_TERM, + 0 +}; + +// Cueille des fleurs. +static Sint16 table_goal_fleur1[] = +{ + EV_ACTION_FLOWER1, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, true, + GOAL_GROUP, 4, + GOAL_TESTOBJECT, 0, -1, CHOBJECT, 81, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 82, -1, -1, DIMOBJY + 20, 1, -1 * 100, + GOAL_SOUND, SOUND_FLOWER, + GOAL_ACTION, ACTION_CUEILLE1, DIRECT_E, + GOAL_ACTION, ACTION_CUEILLE1, DIRECT_S, + GOAL_GOBLUPI, 0, -1, true, + GOAL_SOUND, SOUND_FLOWER, + GOAL_ACTION, ACTION_CUEILLE1, DIRECT_S, + GOAL_ACTION, ACTION_CUEILLE1, DIRECT_E, + GOAL_GOBLUPI, +1, 0, true, + GOAL_SOUND, SOUND_FLOWER, + GOAL_ACTION, ACTION_CUEILLE1, DIRECT_S, + GOAL_ACTION, ACTION_CUEILLE1, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_OTHER, CHOBJECT, 81, 81, -1, -1, EV_ACTION_FLOWER1, + GOAL_TERM, + 0 +}; + +// Cueille des fleurs. +static Sint16 table_goal_fleur2[] = +{ + EV_ACTION_FLOWER2, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, true, + GOAL_GROUP, 4, + GOAL_TESTOBJECT, 0, -1, CHOBJECT, 83, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 84, -1, -1, DIMOBJY + 20, 1, -1 * 100, + GOAL_SOUND, SOUND_FLOWER, + GOAL_ACTION, ACTION_CUEILLE2, DIRECT_E, + GOAL_ACTION, ACTION_CUEILLE2, DIRECT_S, + GOAL_GOBLUPI, 0, -1, true, + GOAL_SOUND, SOUND_FLOWER, + GOAL_ACTION, ACTION_CUEILLE2, DIRECT_S, + GOAL_ACTION, ACTION_CUEILLE2, DIRECT_E, + GOAL_GOBLUPI, +1, 0, true, + GOAL_SOUND, SOUND_FLOWER, + GOAL_ACTION, ACTION_CUEILLE2, DIRECT_S, + GOAL_ACTION, ACTION_CUEILLE2, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_OTHER, CHOBJECT, 83, 83, -1, -1, EV_ACTION_FLOWER2, + GOAL_TERM, + 0 +}; + +// Cueille des fleurs. +static Sint16 table_goal_fleur3[] = +{ + EV_ACTION_FLOWER3, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, true, + GOAL_GROUP, 4, + GOAL_TESTOBJECT, 0, -1, CHOBJECT, 94, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 95, -1, -1, DIMOBJY + 20, 1, -1 * 100, + GOAL_SOUND, SOUND_FLOWER, + GOAL_ACTION, ACTION_CUEILLE3, DIRECT_E, + GOAL_ACTION, ACTION_CUEILLE3, DIRECT_S, + GOAL_GOBLUPI, 0, -1, true, + GOAL_SOUND, SOUND_FLOWER, + GOAL_ACTION, ACTION_CUEILLE3, DIRECT_S, + GOAL_ACTION, ACTION_CUEILLE3, DIRECT_E, + GOAL_GOBLUPI, +1, 0, true, + GOAL_SOUND, SOUND_FLOWER, + GOAL_ACTION, ACTION_CUEILLE3, DIRECT_S, + GOAL_ACTION, ACTION_CUEILLE3, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_OTHER, CHOBJECT, 94, 94, -1, -1, EV_ACTION_FLOWER3, + GOAL_TERM, + 0 +}; + +// Transforme des fleurs. +static Sint16 table_goal_labo[] = +{ + EV_ACTION_LABO, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 6, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 29, // ferme la porte + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 29, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, -1, -1, 10, // secoue + GOAL_CACHE, true, false, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_W, + GOAL_SOUND, SOUND_LABO, + GOAL_ACTION, ACTION_LABO, DIRECT_E, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 4, + GOAL_LABO, + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 28, // ouvre la porte + GOAL_CACHE, false, false, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GOBLUPI, +1, 0, true, + GOAL_IFTERM, 0, -1, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_TERM, + 0 +}; + +// Blupi fait péter la dynamite. +static Sint16 table_goal_dynamite[] = +{ + EV_ACTION_DYNAMITE, + //? GOAL_ENERGY, MAXENERGY/4, + GOAL_GOHILI2, 0, +1, false, + //? GOAL_ENERGY, MAXENERGY/4, + GOAL_GROUP, 5, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_PUTOBJECT, 0, -1, -1, -1, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, -1, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDICONS, 0, -1, 7, // mèche + GOAL_ACTION, ACTION_MECHE, DIRECT_E, + GOAL_SOUND, SOUND_DYNAMITE, + GOAL_GROUP, 4, + GOAL_PUTOBJECT, 0, -1, -1, -1, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, -1, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDICONS, 0, -1, 6, // explosion + GOAL_CACHE, true, true, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_GROUP, 4 + 4, + GOAL_EXPLOSE1, 0, -3, + GOAL_EXPLOSE1, -2, -1, + GOAL_EXPLOSE1, +2, -1, + GOAL_EXPLOSE1, 0, +1, + GOAL_EXPLOSE2, 0, -3, + GOAL_EXPLOSE2, -2, -1, + GOAL_EXPLOSE2, +2, -1, + GOAL_EXPLOSE2, 0, +1, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_GROUP, 4 + 4, + GOAL_EXPLOSE1, -2, -3, + GOAL_EXPLOSE1, +2, -3, + GOAL_EXPLOSE1, -2, +1, + GOAL_EXPLOSE1, +2, +1, + GOAL_EXPLOSE2, -2, -3, + GOAL_EXPLOSE2, +2, -3, + GOAL_EXPLOSE2, -2, +1, + GOAL_EXPLOSE2, +2, +1, + GOAL_ACTION, ACTION_DYNAMITE, DIRECT_E, + GOAL_GROUP, 3, + GOAL_FINISHMOVE, + GOAL_CACHE, false, true, + GOAL_DELETE, // blupi meurt brutalement + GOAL_TERM, + 0 +}; + +// Blupi fait péter la dynamite très fort. +static Sint16 table_goal_dynamite2[] = +{ + EV_ACTION_DYNAMITE2, + //? GOAL_ENERGY, MAXENERGY/4, + GOAL_GOHILI2, 0, +1, false, + //? GOAL_ENERGY, MAXENERGY/4, + GOAL_GROUP, 5, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_PUTOBJECT, 0, -1, -1, -1, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, -1, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDICONS, 0, -1, 7, // mèche + GOAL_ACTION, ACTION_MECHE, DIRECT_E, + GOAL_SOUND, SOUND_DYNAMITE, + GOAL_GROUP, 5, + GOAL_PUTOBJECT, 0, -1, -1, -1, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, -1, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDICONS, 0, -1, 6, // explosion + GOAL_CACHE, true, true, + GOAL_DEPOSE, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_GROUP, 4 + 4, + GOAL_EXPLOSE1, 0, -3, + GOAL_EXPLOSE1, -2, -1, + GOAL_EXPLOSE1, +2, -1, + GOAL_EXPLOSE1, 0, +1, + GOAL_EXPLOSE2, 0, -3, + GOAL_EXPLOSE2, -2, -1, + GOAL_EXPLOSE2, +2, -1, + GOAL_EXPLOSE2, 0, +1, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_GROUP, 4 + 4, + GOAL_EXPLOSE1, -2, -3, + GOAL_EXPLOSE1, +2, -3, + GOAL_EXPLOSE1, -2, +1, + GOAL_EXPLOSE1, +2, +1, + GOAL_EXPLOSE2, -2, -3, + GOAL_EXPLOSE2, +2, -3, + GOAL_EXPLOSE2, -2, +1, + GOAL_EXPLOSE2, +2, +1, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_GROUP, 12 + 12, + GOAL_EXPLOSE1, -4, -3, + GOAL_EXPLOSE1, -4, -1, + GOAL_EXPLOSE1, -4, +1, + GOAL_EXPLOSE1, -2, -5, + GOAL_EXPLOSE1, -2, +3, + GOAL_EXPLOSE1, 0, -5, + GOAL_EXPLOSE1, 0, +3, + GOAL_EXPLOSE1, +2, -5, + GOAL_EXPLOSE1, +2, +3, + GOAL_EXPLOSE1, +4, -3, + GOAL_EXPLOSE1, +4, -1, + GOAL_EXPLOSE1, +4, +1, + GOAL_EXPLOSE2, -4, -3, + GOAL_EXPLOSE2, -4, -1, + GOAL_EXPLOSE2, -4, +1, + GOAL_EXPLOSE2, -2, -5, + GOAL_EXPLOSE2, -2, +3, + GOAL_EXPLOSE2, 0, -5, + GOAL_EXPLOSE2, 0, +3, + GOAL_EXPLOSE2, +2, -5, + GOAL_EXPLOSE2, +2, +3, + GOAL_EXPLOSE2, +4, -3, + GOAL_EXPLOSE2, +4, -1, + GOAL_EXPLOSE2, +4, +1, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_GROUP, 16 + 16, + GOAL_EXPLOSE1, -6, -3, + GOAL_EXPLOSE1, -6, -1, + GOAL_EXPLOSE1, -6, +1, + GOAL_EXPLOSE1, -4, -5, + GOAL_EXPLOSE1, -4, +3, + GOAL_EXPLOSE1, -2, -7, + GOAL_EXPLOSE1, -2, +5, + GOAL_EXPLOSE1, 0, -7, + GOAL_EXPLOSE1, 0, +5, + GOAL_EXPLOSE1, +2, -7, + GOAL_EXPLOSE1, +2, +5, + GOAL_EXPLOSE1, +4, -5, + GOAL_EXPLOSE1, +4, +3, + GOAL_EXPLOSE1, +6, -3, + GOAL_EXPLOSE1, +6, -1, + GOAL_EXPLOSE1, +6, +1, + GOAL_EXPLOSE2, -6, -3, + GOAL_EXPLOSE2, -6, -1, + GOAL_EXPLOSE2, -6, +1, + GOAL_EXPLOSE2, -4, -5, + GOAL_EXPLOSE2, -4, +3, + GOAL_EXPLOSE2, -2, -7, + GOAL_EXPLOSE2, -2, +5, + GOAL_EXPLOSE2, 0, -7, + GOAL_EXPLOSE2, 0, +5, + GOAL_EXPLOSE2, +2, -7, + GOAL_EXPLOSE2, +2, +5, + GOAL_EXPLOSE2, +4, -5, + GOAL_EXPLOSE2, +4, +3, + GOAL_EXPLOSE2, +6, -3, + GOAL_EXPLOSE2, +6, -1, + GOAL_EXPLOSE2, +6, +1, + GOAL_ACTION, ACTION_DYNAMITE, DIRECT_E, + GOAL_GROUP, 3, + GOAL_FINISHMOVE, + GOAL_CACHE, false, true, + GOAL_DELETE, // blupi meurt brutalement + GOAL_TERM, + 0 +}; + +// Tracks fait péter la dynamite. +static Sint16 table_goal_t_dynamite[] = +{ + EV_ACTION_T_DYNAMITE, + GOAL_GOHILI2, +1, +1, false, + GOAL_SOUND, SOUND_DYNAMITE, + GOAL_GROUP, 6, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_PUTOBJECT, -1, -1, -1, -1, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, -1, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDICONS, -1, -1, 6, // explosion + GOAL_CACHE, true, false, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_GROUP, 4 + 4, + GOAL_EXPLOSE1, -1, -3, + GOAL_EXPLOSE1, -3, -1, + GOAL_EXPLOSE1, +1, -1, + GOAL_EXPLOSE1, -1, +1, + GOAL_EXPLOSE2, -1, -3, + GOAL_EXPLOSE2, -3, -1, + GOAL_EXPLOSE2, +1, -1, + GOAL_EXPLOSE2, -1, +1, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_GROUP, 4 + 4, + GOAL_EXPLOSE1, -3, -3, + GOAL_EXPLOSE1, +1, -3, + GOAL_EXPLOSE1, -3, +1, + GOAL_EXPLOSE1, +1, +1, + GOAL_EXPLOSE2, -3, -3, + GOAL_EXPLOSE2, +1, -3, + GOAL_EXPLOSE2, -3, +1, + GOAL_EXPLOSE2, +1, +1, + GOAL_ACTION, ACTION_DYNAMITE, DIRECT_E, + GOAL_GROUP, 3, + GOAL_FINISHMOVE, + GOAL_CACHE, false, false, + GOAL_DELETE, // tracks meurt brutalement + GOAL_TERM, + 0 +}; + +// Blupi amorce une mine. +static Sint16 table_goal_mine[] = +{ + EV_ACTION_MINE, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 3, + GOAL_TESTOBJECT, 0, -1, CHOBJECT, 125, // mine ? + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_ACTION, ACTION_MECHE, DIRECT_E, + GOAL_GROUP, 2, + GOAL_TESTOBJECT, 0, -1, CHOBJECT, 125, // mine ? + GOAL_AMORCE, +1, 0, + GOAL_TERM, + 0 +}; + +// Détonnateur de mine créé par GOAL_AMORCE (blupi invisible). +static Sint16 table_goal_mine2[] = +{ + EV_ACTION_MINE2, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 127, + GOAL_BUILDOBJECT, -1, -1, -1, MOVEICONNB + 10, -1, -1, 100, 1, -1 * 100, + GOAL_SOUND, SOUND_CLICK, + GOAL_ACTION, ACTION_D_DELAY, DIRECT_E, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 125, + GOAL_BUILDOBJECT, -1, -1, -1, MOVEICONNB + 9, -1, -1, 100, 1, -1 * 100, + GOAL_SOUND, SOUND_CLICK, + GOAL_ACTION, ACTION_D_DELAY, DIRECT_E, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 127, + GOAL_BUILDOBJECT, -1, -1, -1, MOVEICONNB + 8, -1, -1, 100, 1, -1 * 100, + GOAL_SOUND, SOUND_CLICK, + GOAL_ACTION, ACTION_D_DELAY, DIRECT_E, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 125, + GOAL_BUILDOBJECT, -1, -1, -1, MOVEICONNB + 7, -1, -1, 100, 1, -1 * 100, + GOAL_SOUND, SOUND_CLICK, + GOAL_ACTION, ACTION_D_DELAY, DIRECT_E, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 127, + GOAL_BUILDOBJECT, -1, -1, -1, MOVEICONNB + 6, -1, -1, 100, 1, -1 * 100, + GOAL_SOUND, SOUND_CLICK, + GOAL_ACTION, ACTION_D_DELAY, DIRECT_E, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 125, + GOAL_BUILDOBJECT, -1, -1, -1, MOVEICONNB + 5, -1, -1, 100, 1, -1 * 100, + GOAL_SOUND, SOUND_CLICK, + GOAL_ACTION, ACTION_D_DELAY, DIRECT_E, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 127, + GOAL_BUILDOBJECT, -1, -1, -1, MOVEICONNB + 4, -1, -1, 100, 1, -1 * 100, + GOAL_SOUND, SOUND_CLICK, + GOAL_ACTION, ACTION_D_DELAY, DIRECT_E, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 125, + GOAL_BUILDOBJECT, -1, -1, -1, MOVEICONNB + 3, -1, -1, 100, 1, -1 * 100, + GOAL_SOUND, SOUND_CLICK, + GOAL_ACTION, ACTION_D_DELAY, DIRECT_E, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 127, + GOAL_BUILDOBJECT, -1, -1, -1, MOVEICONNB + 2, -1, -1, 100, 1, -1 * 100, + GOAL_SOUND, SOUND_CLICK, + GOAL_ACTION, ACTION_D_DELAY, DIRECT_E, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 125, + GOAL_BUILDOBJECT, -1, -1, -1, MOVEICONNB + 1, -1, -1, 100, 1, -1 * 100, + GOAL_SOUND, SOUND_CLICK, + GOAL_ACTION, ACTION_D_DELAY, DIRECT_E, + + GOAL_SOUND, SOUND_DYNAMITE, + GOAL_GROUP, 4, + GOAL_PUTOBJECT, -1, -1, -1, -1, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, -1, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDICONS, -1, -1, 6, // explosion + GOAL_CACHE, true, false, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_GROUP, 4 + 4, + GOAL_EXPLOSE1, -1, -3, + GOAL_EXPLOSE1, -3, -1, + GOAL_EXPLOSE1, +1, -1, + GOAL_EXPLOSE1, -1, +1, + GOAL_EXPLOSE2, -1, -3, + GOAL_EXPLOSE2, -3, -1, + GOAL_EXPLOSE2, +1, -1, + GOAL_EXPLOSE2, -1, +1, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_GROUP, 4 + 4, + GOAL_EXPLOSE1, -3, -3, + GOAL_EXPLOSE1, +1, -3, + GOAL_EXPLOSE1, -3, +1, + GOAL_EXPLOSE1, +1, +1, + GOAL_EXPLOSE2, -3, -3, + GOAL_EXPLOSE2, +1, -3, + GOAL_EXPLOSE2, -3, +1, + GOAL_EXPLOSE2, +1, +1, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_GROUP, 12 + 12, + GOAL_EXPLOSE1, -5, -3, + GOAL_EXPLOSE1, -5, -1, + GOAL_EXPLOSE1, -5, +1, + GOAL_EXPLOSE1, -3, -5, + GOAL_EXPLOSE1, -3, +3, + GOAL_EXPLOSE1, -1, -5, + GOAL_EXPLOSE1, -1, +3, + GOAL_EXPLOSE1, +1, -5, + GOAL_EXPLOSE1, +1, +3, + GOAL_EXPLOSE1, +3, -3, + GOAL_EXPLOSE1, +3, -1, + GOAL_EXPLOSE1, +3, +1, + GOAL_EXPLOSE2, -5, -3, + GOAL_EXPLOSE2, -5, -1, + GOAL_EXPLOSE2, -5, +1, + GOAL_EXPLOSE2, -3, -5, + GOAL_EXPLOSE2, -3, +3, + GOAL_EXPLOSE2, -1, -5, + GOAL_EXPLOSE2, -1, +3, + GOAL_EXPLOSE2, +1, -5, + GOAL_EXPLOSE2, +1, +3, + GOAL_EXPLOSE2, +3, -3, + GOAL_EXPLOSE2, +3, -1, + GOAL_EXPLOSE2, +3, +1, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_DELAY, DIRECT_E, + GOAL_GROUP, 16 + 16, + GOAL_EXPLOSE1, -7, -3, + GOAL_EXPLOSE1, -7, -1, + GOAL_EXPLOSE1, -7, +1, + GOAL_EXPLOSE1, -5, -5, + GOAL_EXPLOSE1, -5, +3, + GOAL_EXPLOSE1, -3, -7, + GOAL_EXPLOSE1, -3, +5, + GOAL_EXPLOSE1, -1, -7, + GOAL_EXPLOSE1, -1, +5, + GOAL_EXPLOSE1, +1, -7, + GOAL_EXPLOSE1, +1, +5, + GOAL_EXPLOSE1, +3, -5, + GOAL_EXPLOSE1, +3, +3, + GOAL_EXPLOSE1, +5, -3, + GOAL_EXPLOSE1, +5, -1, + GOAL_EXPLOSE1, +5, +1, + GOAL_EXPLOSE2, -7, -3, + GOAL_EXPLOSE2, -7, -1, + GOAL_EXPLOSE2, -7, +1, + GOAL_EXPLOSE2, -5, -5, + GOAL_EXPLOSE2, -5, +3, + GOAL_EXPLOSE2, -3, -7, + GOAL_EXPLOSE2, -3, +5, + GOAL_EXPLOSE2, -1, -7, + GOAL_EXPLOSE2, -1, +5, + GOAL_EXPLOSE2, +1, -7, + GOAL_EXPLOSE2, +1, +5, + GOAL_EXPLOSE2, +3, -5, + GOAL_EXPLOSE2, +3, +3, + GOAL_EXPLOSE2, +5, -3, + GOAL_EXPLOSE2, +5, -1, + GOAL_EXPLOSE2, +5, +1, + GOAL_ACTION, ACTION_DYNAMITE, DIRECT_E, + GOAL_GROUP, 3, + GOAL_FINISHMOVE, + GOAL_CACHE, false, false, + GOAL_DELETE, // blupi meurt brutalement + GOAL_TERM, + 0 +}; + +// Construit un pont en direction de l'est. +static Sint16 table_goal_ponte[] = +{ + EV_ACTION_BRIDGEE, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, 0, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, 0, + GOAL_BUILDOBJECT, -1, 0, CHOBJECT, 72, -1, -1, DIMOBJY / 10, 12, -10 * 100, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_GOBLUPI, -1, +1, true, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_GOBLUPI, +1, 0, true, + GOAL_OTHERLOOP, EV_ACTION_BRIDGEEL, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_pontel[] = +{ + EV_ACTION_BRIDGEEL, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_BUILDOBJECT, -10, -10, CHOBJECT, 72, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, -10, -10, 6, // pont vers l'est + GOAL_ACTION, ACTION_BRIDGE, DIRECT_E, + GOAL_GROUP, 4, + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, -10, -10, -1, -1, + GOAL_NEXTLOOP, + GOAL_PUTOBJECT, -10, -10, CHOBJECT, 72, + GOAL_OTHERLOOP, EV_ACTION_BRIDGEEL, + + GOAL_GROUP, 3, + GOAL_PUTOBJECT, -10, -10, -1, -1, + GOAL_PUTFLOOR, -10, -10, CHFLOOR, -2, // vIcon + GOAL_SOUND, SOUND_PLOUF, + //? GOAL_ACTION, 0,-1, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_TERM, + 0 +}; + +// Construit un pont en direction de l'ouest. +static Sint16 table_goal_ponto[] = +{ + EV_ACTION_BRIDGEO, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, 0, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, 0, + GOAL_BUILDOBJECT, -1, 0, CHOBJECT, 72, -1, -1, DIMOBJY / 10, 12, -10 * 100, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_GOBLUPI, -1, +1, true, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_OTHERLOOP, EV_ACTION_BRIDGEOL, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_pontol[] = +{ + EV_ACTION_BRIDGEOL, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_BUILDOBJECT, -10, -10, CHOBJECT, 72, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, -10, -10, 7, // pont vers l'ouest + GOAL_ACTION, ACTION_BRIDGE, DIRECT_W, + GOAL_GROUP, 4, + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, -10, -10, -1, -1, + GOAL_NEXTLOOP, + GOAL_PUTOBJECT, -10, -10, CHOBJECT, 72, + GOAL_OTHERLOOP, EV_ACTION_BRIDGEOL, + + GOAL_GROUP, 3, + GOAL_PUTOBJECT, -10, -10, -1, -1, + GOAL_PUTFLOOR, -10, -10, CHFLOOR, -2, // vIcon + GOAL_SOUND, SOUND_PLOUF, + //? GOAL_GOBLUPI, 0,-1, true, + GOAL_ACTION, ACTION_STOP, DIRECT_W, + GOAL_TERM, + 0 +}; + +// Construit un pont en direction du sud. +static Sint16 table_goal_ponts[] = +{ + EV_ACTION_BRIDGES, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, 0, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, 0, + GOAL_BUILDOBJECT, -1, 0, CHOBJECT, 73, -1, -1, DIMOBJY / 10, 12, -10 * 100, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_GOBLUPI, 0, +1, true, + GOAL_OTHERLOOP, EV_ACTION_BRIDGESL, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_pontsl[] = +{ + EV_ACTION_BRIDGESL, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_BUILDOBJECT, -10, -10, CHOBJECT, 73, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, -10, -10, 8, // pont vers le sud + GOAL_ACTION, ACTION_BRIDGE, DIRECT_S, + GOAL_GROUP, 4, + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, -10, -10, -1, -1, + GOAL_NEXTLOOP, + GOAL_PUTOBJECT, -10, -10, CHOBJECT, 73, + GOAL_OTHERLOOP, EV_ACTION_BRIDGESL, + + GOAL_GROUP, 3, + GOAL_PUTOBJECT, -10, -10, -1, -1, + GOAL_PUTFLOOR, -10, -10, CHFLOOR, -2, // vIcon + GOAL_SOUND, SOUND_PLOUF, + //? GOAL_GOBLUPI, -1,0, true, + GOAL_ACTION, ACTION_STOP, DIRECT_S, + GOAL_TERM, + 0 +}; + +// Construit un pont en direction du nord. +static Sint16 table_goal_pontn[] = +{ + EV_ACTION_BRIDGEN, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, 0, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, 0, + GOAL_BUILDOBJECT, -1, 0, CHOBJECT, 73, -1, -1, DIMOBJY / 10, 12, -10 * 100, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_OTHERLOOP, EV_ACTION_BRIDGENL, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_pontnl[] = +{ + EV_ACTION_BRIDGENL, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_BUILDOBJECT, -10, -10, CHOBJECT, 73, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, -10, -10, 9, // pont vers le nord + GOAL_ACTION, ACTION_BRIDGE, DIRECT_N, + GOAL_GROUP, 4, + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, -10, -10, -1, -1, + GOAL_NEXTLOOP, + GOAL_PUTOBJECT, -10, -10, CHOBJECT, 73, + GOAL_OTHERLOOP, EV_ACTION_BRIDGENL, + + GOAL_GROUP, 3, + GOAL_PUTOBJECT, -10, -10, -1, -1, + GOAL_PUTFLOOR, -10, -10, CHFLOOR, -2, // vIcon + GOAL_SOUND, SOUND_PLOUF, + //? GOAL_GOBLUPI, -1,0, true, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_TERM, + 0 +}; + +// Construit un bateau. +static Sint16 table_goal_bateaue[] = +{ + EV_ACTION_BOATE, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, 0, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, 0, + GOAL_BUILDOBJECT, -1, 0, CHOBJECT, 117, -1, -1, DIMOBJY / 10, 20, -10 * 100, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_GOBLUPI, -1, +1, true, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_GOBLUPI, +1, -1, true, + GOAL_FINISHMOVE, + + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, -1, 0, CHOBJECT, 117, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, -1, 0, 6, // bateau vers l'est + GOAL_ACTION, ACTION_BRIDGE, DIRECT_E, + GOAL_GROUP, 4, + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, -1, 0, -1, -1, + GOAL_PUTOBJECT, +1, 0, CHOBJECT, 117, + GOAL_SOUND, SOUND_PLOUF, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_bateaus[] = +{ + EV_ACTION_BOATS, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, 0, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, 0, + GOAL_BUILDOBJECT, -1, 0, CHOBJECT, 117, -1, -1, DIMOBJY / 10, 20, -10 * 100, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_GOBLUPI, -1, +1, true, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_FINISHMOVE, + + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 117, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, 0, -1, 8, // bateau vers le sud + GOAL_ACTION, ACTION_BRIDGE, DIRECT_S, + GOAL_GROUP, 4, + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, 0, -1, -1, -1, + GOAL_PUTOBJECT, 0, +1, CHOBJECT, 117, + GOAL_SOUND, SOUND_PLOUF, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_bateauo[] = +{ + EV_ACTION_BOATO, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, 0, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, 0, + GOAL_BUILDOBJECT, -1, 0, CHOBJECT, 117, -1, -1, DIMOBJY / 10, 20, -10 * 100, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_GOBLUPI, -1, +1, true, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_GOBLUPI, +1, -1, true, + GOAL_FINISHMOVE, + + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, -1, 0, CHOBJECT, 117, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, -1, 0, 7, // bateau vers l'ouest + GOAL_ACTION, ACTION_BRIDGE, DIRECT_W, + GOAL_GROUP, 4, + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, -1, 0, -1, -1, + GOAL_PUTOBJECT, -3, 0, CHOBJECT, 117, + GOAL_SOUND, SOUND_PLOUF, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_bateaun[] = +{ + EV_ACTION_BOATN, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, 0, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GROUP, 3, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, 0, + GOAL_BUILDOBJECT, -1, 0, CHOBJECT, 117, -1, -1, DIMOBJY / 10, 20, -10 * 100, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_ACTION, ACTION_SAW, DIRECT_S, + GOAL_GOBLUPI, -1, +1, true, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_FINISHMOVE, + + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 117, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, 0, -1, 9, // bateau vers le nord + GOAL_ACTION, ACTION_BRIDGE, DIRECT_N, + GOAL_GROUP, 4, + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, 0, -1, -1, -1, + GOAL_PUTOBJECT, 0, -3, CHOBJECT, 117, + GOAL_SOUND, SOUND_PLOUF, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_TERM, + 0 +}; + +// Départ en bateau. +static Sint16 table_goal_bateaude[] = +{ + EV_ACTION_BOATDE, + GOAL_ISNOMALADE, + GOAL_GOHILI2, +1, +1, true, + GOAL_ISNOMALADE, + GOAL_GROUP, 3, + GOAL_TESTOBJECT, +1, -1, CHOBJECT, 117, + GOAL_INTERRUPT, -1, // passe muraille + GOAL_WORK, +1, -1, + GOAL_GOBLUPI, +2, 0, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 2, + GOAL_PUTOBJECT, -1, -1, -1, -1, // enlève le bateau + GOAL_VEHICULE, 1, // en bateau + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GOBLUPI, +1, 0, true, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_bateauds[] = +{ + EV_ACTION_BOATDS, + GOAL_ISNOMALADE, + GOAL_GOHILI2, +1, +1, false, + GOAL_ISNOMALADE, + GOAL_GROUP, 3, + GOAL_TESTOBJECT, -1, +1, CHOBJECT, 117, + GOAL_INTERRUPT, -1, // passe muraille + GOAL_WORK, -1, +1, + GOAL_GOBLUPI, 0, +2, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 2, + GOAL_PUTOBJECT, -1, -1, -1, -1, // enlève le bateau + GOAL_VEHICULE, 1, // en bateau + GOAL_GOBLUPI, 0, +1, true, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_bateaudo[] = +{ + EV_ACTION_BOATDO, + GOAL_ISNOMALADE, + GOAL_GOHILI2, 0, +1, false, + GOAL_ISNOMALADE, + GOAL_GROUP, 3, + GOAL_TESTOBJECT, -2, -1, CHOBJECT, 117, + GOAL_INTERRUPT, -1, // passe muraille + GOAL_WORK, -2, -1, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 2, + GOAL_PUTOBJECT, -1, -1, -1, -1, // enlève le bateau + GOAL_VEHICULE, 1, // en bateau + GOAL_GOBLUPI, -1, 0, true, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_bateaudn[] = +{ + EV_ACTION_BOATDN, + GOAL_ISNOMALADE, + GOAL_GOHILI2, +1, 0, false, + GOAL_ISNOMALADE, + GOAL_GROUP, 3, + GOAL_TESTOBJECT, -1, -2, CHOBJECT, 117, + GOAL_INTERRUPT, -1, // passe muraille + GOAL_WORK, -1, -2, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 2, + GOAL_PUTOBJECT, -1, -1, -1, -1, // enlève le bateau + GOAL_VEHICULE, 1, // en bateau + GOAL_GOBLUPI, 0, -1, true, + GOAL_TERM, + 0 +}; + +// Arrivée en bateau. +static Sint16 table_goal_bateauae[] = +{ + EV_ACTION_BOATAE, + GOAL_GOHILI2, 0, +1, false, + GOAL_GROUP, 4, + GOAL_IFDEBARQUE, -3, 0, + GOAL_INTERRUPT, -1, // passe muraille + GOAL_WORK, -2, -1, + GOAL_WORK, -4, -1, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 2, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 117, // remet le bateau + GOAL_VEHICULE, 0, // à pied + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GOBLUPI, -2, 0, true, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_bateauas[] = +{ + EV_ACTION_BOATAS, + GOAL_GOHILI2, +1, 0, false, + GOAL_GROUP, 4, + GOAL_IFDEBARQUE, 0, -3, + GOAL_INTERRUPT, -1, // passe muraille + GOAL_WORK, -1, -2, + GOAL_WORK, -1, -4, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 2, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 117, // remet le bateau + GOAL_VEHICULE, 0, // à pied + GOAL_GOBLUPI, 0, -2, true, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_bateauao[] = +{ + EV_ACTION_BOATAO, + GOAL_GOHILI2, 0, +1, false, + GOAL_GROUP, 4, + GOAL_IFDEBARQUE, +2, 0, + GOAL_INTERRUPT, -1, // passe muraille + GOAL_WORK, 0, -1, + GOAL_WORK, +2, -1, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 2, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 117, // remet le bateau + GOAL_VEHICULE, 0, // à pied + GOAL_GOBLUPI, +1, 0, true, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_bateauan[] = +{ + EV_ACTION_BOATAN, + GOAL_GOHILI2, +1, 0, false, + GOAL_GROUP, 4, + GOAL_IFDEBARQUE, 0, +2, + GOAL_INTERRUPT, -1, // passe muraille + GOAL_WORK, -1, 0, + GOAL_WORK, -1, +2, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 2, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 117, // remet le bateau + GOAL_VEHICULE, 0, // à pied + GOAL_GOBLUPI, 0, +1, true, + GOAL_TERM, + 0 +}; + +// Le robot construit une station de recharge. +static Sint16 table_goal_r_build1[] = +{ + EV_ACTION_R_BUILD1, + GOAL_GOHILI2, +1, +1, false, + GOAL_GROUP, 3, + GOAL_USINEBUILD, -1, -1, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_BUILDFLOOR, -1, -1, CHFLOOR, 67, CHMASK1, 0, 16, 14, 1 * 100, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_S, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_S, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_E, + GOAL_GOBLUPI, 0, +1, true, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 99, -1, -1, DIMOBJY / 4, 20, 4 * 100, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_S, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_E, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_W, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_E, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_N, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_TERM, + 0 +}; + +// Le robot construit une usine à araignées. +static Sint16 table_goal_r_build2[] = +{ + EV_ACTION_R_BUILD2, + GOAL_GOHILI2, +1, +1, false, + GOAL_GROUP, 3, + GOAL_USINEBUILD, -1, -1, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_BUILDFLOOR, -1, -1, CHFLOOR, 67, CHMASK1, 0, 16, 14, 1 * 100, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_S, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_S, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_E, + GOAL_GOBLUPI, 0, +1, true, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 100, -1, -1, DIMOBJY / 4, 20, 4 * 100, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_N, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_E, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_W, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_S, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_E, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_S, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_TERM, + 0 +}; + +// Le robot construit une usine à virus. +static Sint16 table_goal_r_build3[] = +{ + EV_ACTION_R_BUILD3, + GOAL_GOHILI2, +1, +1, false, + GOAL_GROUP, 3, + GOAL_USINEBUILD, -1, -1, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_BUILDFLOOR, -1, -1, CHFLOOR, 67, CHMASK1, 0, 16, 14, 1 * 100, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_S, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_S, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_E, + GOAL_GOBLUPI, 0, +1, true, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 102, -1, -1, DIMOBJY / 4, 20, 4 * 100, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_W, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_N, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_S, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_E, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_S, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_TERM, + 0 +}; + +// Le robot construit une usine à tracks. +static Sint16 table_goal_r_build4[] = +{ + EV_ACTION_R_BUILD4, + GOAL_GOHILI2, +1, +1, false, + GOAL_GROUP, 3, + GOAL_USINEBUILD, -1, -1, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_BUILDFLOOR, -1, -1, CHFLOOR, 67, CHMASK1, 0, 16, 14, 1 * 100, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_S, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_S, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_E, + GOAL_GOBLUPI, 0, +1, true, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 104, -1, -1, DIMOBJY / 4, 20, 4 * 100, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_S, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_W, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_S, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_N, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_TERM, + 0 +}; + +// Le robot construit une usine à bombe. +static Sint16 table_goal_r_build5[] = +{ + EV_ACTION_R_BUILD5, + GOAL_GOHILI2, +1, +1, false, + GOAL_GROUP, 3, + GOAL_USINEBUILD, -1, -1, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_BUILDFLOOR, -1, -1, CHFLOOR, 67, CHMASK1, 0, 16, 14, 1 * 100, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_S, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_S, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_E, + GOAL_GOBLUPI, 0, +1, true, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 115, -1, -1, DIMOBJY / 4, 20, 4 * 100, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_S, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_W, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_S, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_N, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_TERM, + 0 +}; + +// Le robot construit une usine à électro. +static Sint16 table_goal_r_build6[] = +{ + EV_ACTION_R_BUILD6, + GOAL_GOHILI2, +1, +1, false, + GOAL_GROUP, 3, + GOAL_USINEBUILD, -1, -1, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_BUILDFLOOR, -1, -1, CHFLOOR, 67, CHMASK1, 0, 16, 14, 1 * 100, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_S, + GOAL_GOBLUPI, -1, 0, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_S, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_E, + GOAL_GOBLUPI, 0, +1, true, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 17, -1, -1, DIMOBJY / 4, 20, 4 * 100, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_S, + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_W, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_S, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_APLAT, DIRECT_N, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_E, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_S, + GOAL_FINISHMOVE, + GOAL_TERM, + 0 +}; + +// Le robot se recharge. +static Sint16 table_goal_r_make1[] = +{ + EV_ACTION_R_MAKE1, + GOAL_GOHILI2, +1, +1, false, + GOAL_GROUP, 2, + GOAL_USINEFREE, -1, -1, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_ACTION, ACTION_R_LOAD, DIRECT_W, + GOAL_ACTION, ACTION_R_LOAD, DIRECT_W, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_W, + GOAL_ACTION, ACTION_R_LOAD, DIRECT_W, + GOAL_ACTION, ACTION_R_LOAD, DIRECT_W, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_W, + GOAL_ACTION, ACTION_R_LOAD, DIRECT_W, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_W, + GOAL_ACTION, ACTION_R_LOAD, DIRECT_W, + GOAL_ACTION, ACTION_R_LOAD, DIRECT_W, + GOAL_ACTION, ACTION_R_BUILD, DIRECT_W, + GOAL_TERM, + 0 +}; + +// Le robot construit une araignée. +static Sint16 table_goal_r_make2[] = +{ + EV_ACTION_R_MAKE2, + GOAL_GOHILI2, +2, +1, false, + GOAL_GROUP, 2, + GOAL_USINEFREE, -2, -1, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_SOUND, SOUND_DOOR, + GOAL_PUTOBJECT, -2, -1, CHOBJECT, 101, // ouvre la porte + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_GOBLUPI, -1, 0, true, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 2, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 100, // ferme la porte + GOAL_CACHE, true, false, + GOAL_GOBLUPI, -1, 0, true, + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 100, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, 0, -1, 10, // secoue + GOAL_SOUND, SOUND_LABO, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 100, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, 0, -1, 10, // secoue + GOAL_SOUND, SOUND_LABO, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_WAITFREE, 2, 0, + GOAL_WAITFREE, 3, 0, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 2, + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, 0, -1, CHOBJECT, 101, // ouvre la porte + GOAL_NEWPERSO, +1, 0, 1, // araignée (qui sortira) + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_SOUND, SOUND_DOOR, + GOAL_PUTOBJECT, 0, -1, CHOBJECT, 100, // ferme la porte + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_WAITFREE, 1, 0, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 2, + GOAL_CACHE, false, false, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 101, // ouvre la porte + GOAL_GOBLUPI, +1, 0, true, + GOAL_SOUND, SOUND_DOOR, + GOAL_PUTOBJECT, -2, -1, CHOBJECT, 100, // ferme la porte + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_TERM, + 0 +}; + +// Le robot construit un virus. +static Sint16 table_goal_r_make3[] = +{ + EV_ACTION_R_MAKE3, + GOAL_GOHILI2, +2, +1, false, + GOAL_GROUP, 2, + GOAL_USINEFREE, -2, -1, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_SOUND, SOUND_DOOR, + GOAL_PUTOBJECT, -2, -1, CHOBJECT, 103, // ouvre la porte + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_GOBLUPI, -1, 0, true, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 2, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 102, // ferme la porte + GOAL_CACHE, true, false, + GOAL_GOBLUPI, -1, 0, true, + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 102, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, 0, -1, 10, // secoue + GOAL_SOUND, SOUND_LABO, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 102, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, 0, -1, 10, // secoue + GOAL_SOUND, SOUND_LABO, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_WAITFREE, 2, 0, + GOAL_WAITFREE, 3, 0, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 2, + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, 0, -1, CHOBJECT, 103, // ouvre la porte + GOAL_NEWPERSO, +1, 0, 2, // virus (qui sortira) + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_SOUND, SOUND_DOOR, + GOAL_PUTOBJECT, 0, -1, CHOBJECT, 102, // ferme la porte + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_WAITFREE, 1, 0, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 2, + GOAL_CACHE, false, false, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 103, // ouvre la porte + GOAL_GOBLUPI, +1, 0, true, + GOAL_SOUND, SOUND_DOOR, + GOAL_PUTOBJECT, -2, -1, CHOBJECT, 102, // ferme la porte + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_TERM, + 0 +}; + +// Le robot construit un tracks. +static Sint16 table_goal_r_make4[] = +{ + EV_ACTION_R_MAKE4, + GOAL_GOHILI2, +2, +1, false, + GOAL_GROUP, 2, + GOAL_USINEFREE, -2, -1, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_SOUND, SOUND_DOOR, + GOAL_PUTOBJECT, -2, -1, CHOBJECT, 105, // ouvre la porte + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_GOBLUPI, -1, 0, true, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 2, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 104, // ferme la porte + GOAL_CACHE, true, false, + GOAL_GOBLUPI, -1, 0, true, + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 104, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, 0, -1, 10, // secoue + GOAL_SOUND, SOUND_LABO, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 104, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, 0, -1, 10, // secoue + GOAL_SOUND, SOUND_LABO, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_WAITFREE, 2, 0, + GOAL_WAITFREE, 3, 0, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 2, + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, 0, -1, CHOBJECT, 105, // ouvre la porte + GOAL_NEWPERSO, +1, 0, 3, // tracks (qui sortira) + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_SOUND, SOUND_DOOR, + GOAL_PUTOBJECT, 0, -1, CHOBJECT, 104, // ferme la porte + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_WAITFREE, 1, 0, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 2, + GOAL_CACHE, false, false, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 105, // ouvre la porte + GOAL_GOBLUPI, +1, 0, true, + GOAL_SOUND, SOUND_DOOR, + GOAL_PUTOBJECT, -2, -1, CHOBJECT, 104, // ferme la porte + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_TERM, + 0 +}; + +// Le robot construit une bombe. +static Sint16 table_goal_r_make5[] = +{ + EV_ACTION_R_MAKE5, + GOAL_GOHILI2, +2, +1, false, + GOAL_GROUP, 2, + GOAL_USINEFREE, -2, -1, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_SOUND, SOUND_DOOR, + GOAL_PUTOBJECT, -2, -1, CHOBJECT, 116, // ouvre la porte + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_GOBLUPI, -1, 0, true, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 2, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 115, // ferme la porte + GOAL_CACHE, true, false, + GOAL_GOBLUPI, -1, 0, true, + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 115, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, 0, -1, 10, // secoue + GOAL_SOUND, SOUND_LABO, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 115, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, 0, -1, 10, // secoue + GOAL_SOUND, SOUND_LABO, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_WAITFREE, 2, 0, + GOAL_WAITFREE, 3, 0, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 2, + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, 0, -1, CHOBJECT, 116, // ouvre la porte + GOAL_NEWPERSO, +1, 0, 5, // bombe (qui sortira) + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_SOUND, SOUND_DOOR, + GOAL_PUTOBJECT, 0, -1, CHOBJECT, 115, // ferme la porte + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_WAITFREE, 1, 0, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 2, + GOAL_CACHE, false, false, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 116, // ouvre la porte + GOAL_GOBLUPI, +1, 0, true, + GOAL_SOUND, SOUND_DOOR, + GOAL_PUTOBJECT, -2, -1, CHOBJECT, 115, // ferme la porte + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_TERM, + 0 +}; + +// Le robot construit un électro. +static Sint16 table_goal_r_make6[] = +{ + EV_ACTION_R_MAKE6, + GOAL_GOHILI2, +2, +1, false, + GOAL_GROUP, 2, + GOAL_USINEFREE, -2, -1, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_SOUND, SOUND_DOOR, + GOAL_PUTOBJECT, -2, -1, CHOBJECT, 18, // ouvre la porte + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_ACTION, ACTION_R_STOP, DIRECT_W, + GOAL_GOBLUPI, -1, 0, true, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 2, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 17, // ferme la porte + GOAL_CACHE, true, false, + GOAL_GOBLUPI, -1, 0, true, + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 17, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, 0, -1, 10, // secoue + GOAL_SOUND, SOUND_LABO, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 17, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, 0, -1, 10, // secoue + GOAL_SOUND, SOUND_LABO, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_WAITFREE, 2, 0, + GOAL_WAITFREE, 3, 0, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 2, + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, 0, -1, CHOBJECT, 18, // ouvre la porte + GOAL_NEWPERSO, +1, 0, 7, // électro (qui sortira) + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_SOUND, SOUND_DOOR, + GOAL_PUTOBJECT, 0, -1, CHOBJECT, 17, // ferme la porte + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_WAITFREE, 1, 0, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 2, + GOAL_CACHE, false, false, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 18, // ouvre la porte + GOAL_GOBLUPI, +1, 0, true, + GOAL_SOUND, SOUND_DOOR, + GOAL_PUTOBJECT, -2, -1, CHOBJECT, 17, // ferme la porte + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_ACTION, ACTION_R_STOP, DIRECT_N, + GOAL_TERM, + 0 +}; + +// Blupi monte dans une jeep. +static Sint16 table_goal_mjeep[] = +{ + EV_ACTION_MJEEP, + GOAL_ISNOMALADE, + GOAL_GOHILI2, +1, 0, false, + GOAL_ISNOMALADE, + GOAL_GROUP, 3, + GOAL_TESTOBJECT, -1, 0, CHOBJECT, 118, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, 0, + GOAL_ACTION, ACTION_JUMPJEEP, DIRECT_S, + GOAL_GROUP, 2, + GOAL_PUTOBJECT, -1, -1, -1, -1, // enlève la jeep + GOAL_VEHICULE, 2, // en jeep + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_TERM, + 0 +}; + +// Blupi descend de la jeep. +static Sint16 table_goal_djeep[] = +{ + EV_ACTION_DJEEP, + GOAL_GOHILI2, +1, +1, false, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 5, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 118, // remet la jeep + GOAL_VEHICULE, 0, // à pied + GOAL_ACTUALISE, + GOAL_ACTION, ACTION_JUMPJEEP, DIRECT_N, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_TERM, + 0 +}; + +// Blupi monte dans une armure. +static Sint16 table_goal_marmure[] = +{ + EV_ACTION_MARMURE, + GOAL_ISNOMALADE, + GOAL_GOHILI2, +1, 0, false, + GOAL_ISNOMALADE, + GOAL_GROUP, 3, + GOAL_TESTOBJECT, -1, 0, CHOBJECT, 16, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, 0, + GOAL_GOBLUPI, 0, +1, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 2, + GOAL_PUTOBJECT, -1, -1, -1, -1, // enlève l'armure + GOAL_ACTION, ACTION_ARMORCLOSE, DIRECT_E, + GOAL_VEHICULE, 3, // en armure + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_TERM, + 0 +}; + +// Blupi descend de l'armure. +static Sint16 table_goal_darmure[] = +{ + EV_ACTION_DARMURE, + GOAL_GOHILI2, +1, +1, false, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_ARMOROPEN, DIRECT_E, + GOAL_GROUP, 3, + GOAL_WORK, -1, -1, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 16, // remet l'armure + GOAL_VEHICULE, 0, // à pied + GOAL_GOBLUPI, 0, -1, true, + GOAL_TERM, + 0 +}; + +// Blupi cherche où planter des drapeaux. +static Sint16 table_goal_drapeau[] = +{ + EV_ACTION_FLAG, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_FIX, 0, -1, + GOAL_REPEAT, true, + GOAL_OTHERFIX, CHFLOOR, 33, 48, 71, 71, EV_ACTION_FLAG2, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_drapeau2[] = +{ + EV_ACTION_FLAG2, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 2, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_GOBLUPI, +1, -1, true, + GOAL_ACTION, ACTION_BUILD, DIRECT_S, + GOAL_FLOORJUMP, CHFLOOR, 71, EV_ACTION_FLAG3, + GOAL_ADDDRAPEAU, -1, 0, + + GOAL_OTHERFIX, CHFLOOR, 33, 48, 71, 71, EV_ACTION_FLAG2, + GOAL_TERM, + 0 +}; + +// Plante un drapeau. +static Sint16 table_goal_drapeau3[] = +{ + EV_ACTION_FLAG3, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, 0, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GROUP, 2, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, 0, -1, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 124, -1, -1, DIMOBJY / 10, 8, 10 * 100, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_W, + GOAL_GOBLUPI, +1, -1, true, + GOAL_ACTION, ACTION_PIOCHESOURD, DIRECT_E, + GOAL_ADDDRAPEAU, -1, 0, + GOAL_FINISHMOVE, + + //? GOAL_OTHERFIX, CHFLOOR,33,48,71,71, EV_ACTION_FLAG2, + GOAL_TERM, + 0 +}; + +// Blupi extrait du fer. +static Sint16 table_goal_extrait[] = +{ + EV_ACTION_EXTRAIT, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 6, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 121, // ferme la porte + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 121, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, -1, -1, 11, // secoue + GOAL_CACHE, true, false, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_W, + GOAL_SOUND, SOUND_MINE, + GOAL_ACTION, ACTION_LABO, DIRECT_E, + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 121, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, -1, -1, 11, // secoue + GOAL_SOUND, SOUND_MINE, + GOAL_ACTION, ACTION_LABO, DIRECT_E, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 4, + GOAL_TAKEOBJECT, -1, -1, CHOBJECT, 123, // porte du fer + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 122, // ouvre la porte + GOAL_CACHE, false, false, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GOBLUPI, +1, 0, true, + GOAL_IFTERM, 0, -1, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_TERM, + 0 +}; + +// Blupi fabrique une jeep. +static Sint16 table_goal_fabjeep[] = +{ + EV_ACTION_FABJEEP, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 6, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 119, // ferme la porte + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 119, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, -1, -1, 12, // secoue + GOAL_CACHE, true, false, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_W, + GOAL_SOUND, SOUND_USINE, + GOAL_ACTION, ACTION_LABO, DIRECT_E, + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 119, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, -1, -1, 12, // secoue + GOAL_SOUND, SOUND_USINE, + GOAL_ACTION, ACTION_LABO, DIRECT_E, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 5, + GOAL_TAKEOBJECT, -1, -1, -1, -1, // ne porte plus rien + GOAL_VEHICULE, 2, // en jeep + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 120, // ouvre la porte + GOAL_CACHE, false, false, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GOBLUPI, +1, 0, true, + GOAL_IFTERM, +1, 0, + GOAL_GOBLUPI, +1, 0, true, + GOAL_TERM, + 0 +}; + +// Blupi fabrique une armure. +static Sint16 table_goal_fabarmure[] = +{ + EV_ACTION_FABARMURE, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 6, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 119, // ferme la porte + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 119, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, -1, -1, 12, // secoue + GOAL_CACHE, true, false, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_W, + GOAL_SOUND, SOUND_USINE, + GOAL_ACTION, ACTION_LABO, DIRECT_E, + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 119, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, -1, -1, 12, // secoue + GOAL_SOUND, SOUND_USINE, + GOAL_ACTION, ACTION_LABO, DIRECT_E, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 5, + GOAL_TAKEOBJECT, -1, -1, -1, -1, // ne porte plus rien + GOAL_VEHICULE, 3, // en armure + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 120, // ouvre la porte + GOAL_CACHE, false, false, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GOBLUPI, +1, 0, true, + GOAL_IFTERM, +1, 0, + GOAL_GOBLUPI, +1, 0, true, + GOAL_TERM, + 0 +}; + +// Blupi fabrique une mine. +static Sint16 table_goal_fabmine[] = +{ + EV_ACTION_FABMINE, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 6, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 119, // ferme la porte + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 119, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, -1, -1, 12, // secoue + GOAL_CACHE, true, false, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_W, + GOAL_SOUND, SOUND_USINE, + GOAL_ACTION, ACTION_LABO, DIRECT_E, + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, -1, -1, CHOBJECT, 119, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, -1, -1, 12, // secoue + GOAL_SOUND, SOUND_USINE, + GOAL_ACTION, ACTION_LABO, DIRECT_E, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 4, + GOAL_TAKEOBJECT, -1, -1, CHOBJECT, 125, // porte une mine + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 120, // ouvre la porte + GOAL_CACHE, false, false, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_GOBLUPI, +1, 0, true, + GOAL_IFTERM, 0, -1, + GOAL_GOBLUPI, 0, -1, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_TERM, + 0 +}; + +// Blupi fabrique un disciple. +static Sint16 table_goal_fabdisc[] = +{ + EV_ACTION_FABDISC, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_GOHILI2, +1, +1, false, + GOAL_ENERGY, MAXENERGY / 4, + GOAL_ACTION, ACTION_STOP, DIRECT_N, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 4, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_WORK, -1, -1, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 119, // ferme la porte + GOAL_CACHE, true, false, + GOAL_GOBLUPI, -1, 0, true, + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 119, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, 0, -1, 12, // secoue + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_W, + GOAL_SOUND, SOUND_USINE, + GOAL_ACTION, ACTION_LABO, DIRECT_E, + GOAL_GROUP, 2, + GOAL_BUILDOBJECT, 0, -1, CHOBJECT, 119, -1, -1, DIMOBJY, 1, -1 * 100, + GOAL_ADDMOVES, 0, -1, 12, // secoue + GOAL_SOUND, SOUND_USINE, + GOAL_ACTION, ACTION_LABO, DIRECT_E, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 2, + GOAL_FINISHMOVE, + GOAL_PUTOBJECT, 0, -1, CHOBJECT, 120, // ouvre la porte + GOAL_NEWPERSO, +1, 0, 8, // disciple (qui sortira) + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_SOUND, SOUND_DOOR, + GOAL_PUTOBJECT, 0, -1, CHOBJECT, 119, // ferme la porte + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_ACTION, ACTION_R_DELAY, DIRECT_E, + GOAL_SOUND, SOUND_DOOR, + GOAL_GROUP, 3, + GOAL_TAKEOBJECT, -1, -1, -1, -1, // ne porte plus rien + GOAL_CACHE, false, false, + GOAL_PUTOBJECT, -1, -1, CHOBJECT, 120, // ouvre la porte + GOAL_GOBLUPI, +1, 0, true, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_TERM, + 0 +}; + +// L'électro va sur un blupi puis lance ses rayons. +static Sint16 table_goal_e_rayon[] = +{ + EV_ACTION_E_RAYON, + GOAL_GOHILI2, 0, 0, false, + GOAL_SOUND, SOUND_E_TOURNE, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_BEGIN, DIRECT_E, + GOAL_ACTION, ACTION_E_BEGIN, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_BEGIN, DIRECT_E, + GOAL_ACTION, ACTION_E_BEGIN, DIRECT_E, + GOAL_ACTION, ACTION_E_BEGIN, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_BEGIN, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_BEGIN, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_BEGIN, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_SKIPSKILL, 1, 7, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_BEGIN, DIRECT_E, + GOAL_ACTION, ACTION_E_BEGIN, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_BEGIN, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_SOUND, SOUND_E_RAYON, + GOAL_ELECTRO, 0, 0, 8, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ELECTRO, -2, 0, 8, + GOAL_ELECTRO, 0, -2, 8, + GOAL_ELECTRO, 0, +2, 8, + GOAL_ELECTRO, +2, 0, 8, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ELECTRO, -2, -2, 8, + GOAL_ELECTRO, +2, -2, 8, + GOAL_ELECTRO, -2, +2, 8, + GOAL_ELECTRO, +2, +2, 8, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ELECTRO, -4, -2, 8, + GOAL_ELECTRO, -4, 0, 8, + GOAL_ELECTRO, -4, +2, 8, + GOAL_ELECTRO, -2, -4, 8, + GOAL_ELECTRO, -2, +4, 8, + GOAL_ELECTRO, 0, -4, 8, + GOAL_ELECTRO, 0, +4, 8, + GOAL_ELECTRO, +2, -4, 8, + GOAL_ELECTRO, +2, +4, 8, + GOAL_ELECTRO, +4, -2, 8, + GOAL_ELECTRO, +4, 0, 8, + GOAL_ELECTRO, +4, +2, 8, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ELECTRO, -6, -2, 8, + GOAL_ELECTRO, -6, 0, 8, + GOAL_ELECTRO, -6, +2, 8, + GOAL_ELECTRO, -4, -4, 8, + GOAL_ELECTRO, -4, +4, 8, + GOAL_ELECTRO, -2, -6, 8, + GOAL_ELECTRO, -2, +6, 8, + GOAL_ELECTRO, 0, -6, 8, + GOAL_ELECTRO, 0, +6, 8, + GOAL_ELECTRO, +2, -6, 8, + GOAL_ELECTRO, +2, +6, 8, + GOAL_ELECTRO, +4, -4, 8, + GOAL_ELECTRO, +4, +4, 8, + GOAL_ELECTRO, +6, -2, 8, + GOAL_ELECTRO, +6, 0, 8, + GOAL_ELECTRO, +6, +2, 8, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_ACTION, ACTION_E_RAYON, DIRECT_E, + GOAL_FINISHMOVE, + GOAL_TERM, + 0 +}; + +// Blupi s'électrocute. +static Sint16 table_goal_electro[] = +{ + EV_ACTION_ELECTRO, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_ACTION, ACTION_STOP, DIRECT_SE, + GOAL_MALADE, false, + GOAL_ACTION, ACTION_ELECTRO, DIRECT_SE, + GOAL_TAKEOBJECT, -1, -1, -1, -1, // ne porte plus rien + GOAL_SOUND, SOUND_TCHAO, + GOAL_ACTION, ACTION_GRILL1, DIRECT_SE, + GOAL_ACTION, ACTION_GRILL2, DIRECT_SE, + GOAL_ACTION, ACTION_GRILL3, DIRECT_SE, + GOAL_DELETE, // blupi meurt brutalement + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_electrom[] = +{ + EV_ACTION_ELECTROm, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_ACTION, ACTION_STOP, DIRECT_SE, + GOAL_GROUP, 3, + GOAL_MALADE, false, + GOAL_TAKEOBJECT, -1, -1, -1, -1, // ne porte plus rien + GOAL_SOUND, SOUND_TCHAO, + GOAL_ACTION, ACTION_GRILL1, DIRECT_SE, + GOAL_ACTION, ACTION_GRILL2, DIRECT_SE, + GOAL_ACTION, ACTION_GRILL3, DIRECT_SE, + GOAL_DELETE, // blupi meurt brutalement + GOAL_TERM, + 0 +}; + +// Blupi grille. +static Sint16 table_goal_grille[] = +{ + EV_ACTION_GRILLE, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_ACTION, ACTION_STOP, DIRECT_SE, + GOAL_GROUP, 3, + GOAL_MALADE, false, + GOAL_TAKEOBJECT, -1, -1, -1, -1, // ne porte plus rien + GOAL_SOUND, SOUND_BURN, + GOAL_ACTION, ACTION_GRILL1, DIRECT_SE, + GOAL_ACTION, ACTION_GRILL2, DIRECT_SE, + GOAL_ACTION, ACTION_GRILL3, DIRECT_SE, + GOAL_DELETE, // blupi meurt brutalement + GOAL_TERM, + 0 +}; + +// L'araignée meurt. +static Sint16 table_goal_a_mort[] = +{ + EV_ACTION_A_MORT, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_ACTION, ACTION_STOP, DIRECT_E, + GOAL_SOUND, SOUND_A_POISON, + GOAL_ACTION, ACTION_S_POISON, DIRECT_E, + GOAL_ACTION, ACTION_S_DEAD1, DIRECT_E, + GOAL_ACTION, ACTION_S_DEAD2, DIRECT_E, + GOAL_ACTION, ACTION_S_DEAD3, DIRECT_E, + GOAL_DELETE, // l'araignée meurt brutalement + GOAL_TERM, + 0 +}; + +// Blupi se prépare à répéter une liste. +static Sint16 table_goal_repeat[] = +{ + EV_ACTION_REPEAT, + GOAL_TERM, + 0 +}; + +// Blupi se téléporte d'un endroit à un autre. +static Sint16 table_goal_teleporte00[] = +{ + EV_ACTION_TELEPORTE00, + GOAL_GOHILI2, 0, 0, false, + GOAL_GROUP, 4, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_BUILDFLOOR, 0, 0, CHFLOOR, -1, -1, -1, 100, 1, 1 * 100, + GOAL_ADDICONS, 0, 0, 11, + GOAL_SOUND, SOUND_TELEPORTE, + GOAL_ACTION, ACTION_TELEPORTE1, DIRECT_E, + GOAL_ACTION, ACTION_TELEPORTE2, DIRECT_E, + GOAL_ACTION, ACTION_TELEPORTE3, DIRECT_E, + GOAL_TELEPORTE, 0, 0, + GOAL_GROUP, 3, + GOAL_BUILDFLOOR, 0, 0, CHFLOOR, -1, -1, -1, 60, 1, 1 * 60, + GOAL_ADDICONS, 0, 0, 11, + GOAL_SOUND, SOUND_TELEPORTE, + GOAL_ACTION, ACTION_TELEPORTE2, DIRECT_E, + GOAL_ACTION, ACTION_TELEPORTE1, DIRECT_E, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_teleporte10[] = +{ + EV_ACTION_TELEPORTE10, + GOAL_GOHILI2, +1, 0, false, + GOAL_GROUP, 4, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_BUILDFLOOR, -1, 0, CHFLOOR, -1, -1, -1, 100, 1, 1 * 100, + GOAL_ADDICONS, -1, 0, 11, + GOAL_SOUND, SOUND_TELEPORTE, + GOAL_ACTION, ACTION_TELEPORTE1, DIRECT_E, + GOAL_ACTION, ACTION_TELEPORTE2, DIRECT_E, + GOAL_ACTION, ACTION_TELEPORTE3, DIRECT_E, + GOAL_TELEPORTE, +1, 0, + GOAL_GROUP, 3, + GOAL_BUILDFLOOR, -1, 0, CHFLOOR, -1, -1, -1, 60, 1, 1 * 60, + GOAL_ADDICONS, -1, 0, 11, + GOAL_SOUND, SOUND_TELEPORTE, + GOAL_ACTION, ACTION_TELEPORTE2, DIRECT_E, + GOAL_ACTION, ACTION_TELEPORTE1, DIRECT_E, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_teleporte01[] = +{ + EV_ACTION_TELEPORTE01, + GOAL_GOHILI2, 0, +1, false, + GOAL_GROUP, 4, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_BUILDFLOOR, 0, -1, CHFLOOR, -1, -1, -1, 100, 1, 1 * 100, + GOAL_ADDICONS, 0, -1, 11, + GOAL_SOUND, SOUND_TELEPORTE, + GOAL_ACTION, ACTION_TELEPORTE1, DIRECT_E, + GOAL_ACTION, ACTION_TELEPORTE2, DIRECT_E, + GOAL_ACTION, ACTION_TELEPORTE3, DIRECT_E, + GOAL_TELEPORTE, 0, +1, + GOAL_GROUP, 3, + GOAL_BUILDFLOOR, 0, -1, CHFLOOR, -1, -1, -1, 60, 1, 1 * 60, + GOAL_ADDICONS, 0, -1, 11, + GOAL_SOUND, SOUND_TELEPORTE, + GOAL_ACTION, ACTION_TELEPORTE2, DIRECT_E, + GOAL_ACTION, ACTION_TELEPORTE1, DIRECT_E, + GOAL_TERM, + 0 +}; + +static Sint16 table_goal_teleporte11[] = +{ + EV_ACTION_TELEPORTE11, + GOAL_GOHILI2, +1, +1, false, + GOAL_GROUP, 4, + GOAL_INTERRUPT, 0, // prioritaire + GOAL_BUILDFLOOR, -1, -1, CHFLOOR, -1, -1, -1, 100, 1, 1 * 100, + GOAL_ADDICONS, -1, -1, 11, + GOAL_SOUND, SOUND_TELEPORTE, + GOAL_ACTION, ACTION_TELEPORTE1, DIRECT_E, + GOAL_ACTION, ACTION_TELEPORTE2, DIRECT_E, + GOAL_ACTION, ACTION_TELEPORTE3, DIRECT_E, + GOAL_TELEPORTE, +1, +1, + GOAL_GROUP, 3, + GOAL_BUILDFLOOR, -1, -1, CHFLOOR, -1, -1, -1, 60, 1, 1 * 60, + GOAL_ADDICONS, -1, -1, 11, + GOAL_SOUND, SOUND_TELEPORTE, + GOAL_ACTION, ACTION_TELEPORTE2, DIRECT_E, + GOAL_ACTION, ACTION_TELEPORTE1, DIRECT_E, + GOAL_TERM, + 0 +}; + + +static Sint16 *table_pGoal[] = +{ + table_goal_go, + table_goal_maison, + table_goal_abat1, + table_goal_abat2, + table_goal_abat3, + table_goal_abat4, + table_goal_abat5, + table_goal_abat6, + table_goal_roc1, + table_goal_roc2, + table_goal_roc3, + table_goal_roc4, + table_goal_roc5, + table_goal_roc6, + table_goal_roc7, + table_goal_build1, + table_goal_build2, + table_goal_build3, + table_goal_build4, + table_goal_build5, + table_goal_build6, + table_goal_mur, + table_goal_tour, + table_goal_palis, + table_goal_carry, + table_goal_carry2, + table_goal_depose, + table_goal_depose2, + table_goal_newblupi, + table_goal_cultive, + table_goal_cultive2, + table_goal_mange, + table_goal_mange2, + table_goal_boit, + table_goal_boit2, + table_goal_fleur1, + table_goal_fleur2, + table_goal_fleur3, + table_goal_labo, + table_goal_dynamite, + table_goal_dynamite2, + table_goal_t_dynamite, + table_goal_mine, + table_goal_mine2, + table_goal_ponte, + table_goal_pontel, + table_goal_ponto, + table_goal_pontol, + table_goal_ponts, + table_goal_pontsl, + table_goal_pontn, + table_goal_pontnl, + table_goal_bateaue, + table_goal_bateaus, + table_goal_bateauo, + table_goal_bateaun, + table_goal_bateaude, + table_goal_bateauds, + table_goal_bateaudo, + table_goal_bateaudn, + table_goal_bateauae, + table_goal_bateauas, + table_goal_bateauao, + table_goal_bateauan, + table_goal_r_build1, + table_goal_r_build2, + table_goal_r_build3, + table_goal_r_build4, + table_goal_r_build5, + table_goal_r_build6, + table_goal_r_make1, + table_goal_r_make2, + table_goal_r_make3, + table_goal_r_make4, + table_goal_r_make5, + table_goal_r_make6, + table_goal_mjeep, + table_goal_djeep, + table_goal_marmure, + table_goal_darmure, + table_goal_drapeau, + table_goal_drapeau2, + table_goal_drapeau3, + table_goal_extrait, + table_goal_fabjeep, + table_goal_fabarmure, + table_goal_fabmine, + table_goal_fabdisc, + table_goal_e_rayon, + table_goal_electro, + table_goal_electrom, + table_goal_grille, + table_goal_a_mort, + table_goal_repeat, + table_goal_teleporte00, + table_goal_teleporte10, + table_goal_teleporte01, + table_goal_teleporte11, + nullptr +}; +// clang-format on + +// Retourne le pointeur à la table table_goal_*. + +Sint16 * +GetTableGoal (Sint32 action) +{ + Sint16 ** ppTable = table_pGoal; + + while (*ppTable != nullptr) + { + if (**ppTable == action) + { + return *ppTable + 1; // après EV_ACTION_* + } + + ppTable++; + } + + return nullptr; +} diff --git a/src/decgoal.h b/src/decgoal.h new file mode 100644 index 0000000..94f87b8 --- /dev/null +++ b/src/decgoal.h @@ -0,0 +1,81 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include + +// Méta opérations (goal). + +// clang-format off +#define GOAL_TERM 0 // +#define GOAL_GOHILI 1 // dx,dy, bPass +#define GOAL_GOHILI2 2 // dx,dy, bPass +#define GOAL_GOBLUPI 3 // dx,dy, bPass +#define GOAL_PUTFLOOR 4 // dx,dy, channel,icon +#define GOAL_PUTOBJECT 5 // dx,dy, channel,icon +#define GOAL_BUILDFLOOR 6 // dx,dy, ch,i,mch, mi,total,delai,step +#define GOAL_BUILDOBJECT 7 // dx,dy, ch,i,mch, mi,total,delai,step +#define GOAL_ACTION 8 // action,direction +#define GOAL_INTERRUPT 9 // niveau (0..2) +#define GOAL_ENERGY 10 // niveau minimum requis +#define GOAL_ADDMOVES 11 // dx,dy,no +#define GOAL_OTHER 12 // channel,first,last,fitst,last,action +#define GOAL_FINISHMOVE 13 // +#define GOAL_TAKE 14 // dx,dy +#define GOAL_DEPOSE 15 // +#define GOAL_GROUP 16 // nb +#define GOAL_WORK 17 // dx,dy +#define GOAL_TESTOBJECT 18 // dx,dy, channel,icon +#define GOAL_FIX 19 // dx,dy +#define GOAL_OTHERFIX 20 // channel,first,last,first,last,action +#define GOAL_ADDICONS 21 // dx,dy,no +#define GOAL_NEWBLUPI 22 // dx,dy +#define GOAL_SOUND 23 // sound +#define GOAL_REPEAT 24 // true/false +#define GOAL_OTHERLOOP 25 // action +#define GOAL_NEXTLOOP 26 // +#define GOAL_ARRANGEOBJECT 27 // dx,dy +#define GOAL_LABO 28 // +#define GOAL_CACHE 29 // true/false, bDynamite +#define GOAL_DELETE 30 // +#define GOAL_ELECTRO 31 // dx,dy,no +#define GOAL_NEWPERSO 32 // dx,dy, perso +#define GOAL_USINEBUILD 33 // dx,dy, +#define GOAL_USINEFREE 34 // dx,dy, +#define GOAL_EXPLOSE1 35 // dx,dy +#define GOAL_EXPLOSE2 36 // dx,dy +#define GOAL_VEHICULE 37 // type +#define GOAL_TAKEOBJECT 38 // dx,dy, channel,icon +#define GOAL_FLOORJUMP 39 // channel,icon,action +#define GOAL_ADDDRAPEAU 40 // dx,dy +#define GOAL_AMORCE 41 // dx,dy +#define GOAL_MALADE 42 // bMalade +#define GOAL_IFTERM 43 // dx,dy +#define GOAL_IFDEBARQUE 44 // dx,dy +#define GOAL_ISNOMALADE 45 // +#define GOAL_SKIPSKILL 46 // skill,d +#define GOAL_TELEPORTE 47 // dx,dy +#define GOAL_ACTUALISE 48 // +#define GOAL_WAITFREE 49 // dx,dy +// clang-format on + +Sint16 * GetTableGoal (Sint32 action); +extern Sint16 table_goal_nbop[]; diff --git a/src/decio.cxx b/src/decio.cxx new file mode 100644 index 0000000..7978f70 --- /dev/null +++ b/src/decio.cxx @@ -0,0 +1,525 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "decor.h" +#include "def.h" +#include "misc.h" + +typedef struct { + Sint16 majRev; + Sint16 minRev; + Sint32 nbDecor; + Sint32 lgDecor; + Sint32 nbBlupi; + Sint32 lgBlupi; + Sint32 nbMove; + Sint32 lgMove; + Sint16 reserve1[100]; + Point celCoin; + Sint16 world; + Sint32 time; + char buttonExist[MAXBUTTON]; + Term term; + Sint16 music; + Sint16 region; + Sint32 totalTime; + Sint16 skill; + Point memoPos[4]; + Sint16 reserve2[29]; +} DescFile; + +typedef struct { + Sint32 bExist; // true -> utilisé + Sint32 bHili; // true -> sélectionné + + Sint16 perso; // personnage, voir (*) + + Sint16 goalAction; // action (Sint32 terme) + Sint16 goalPhase; // phase (Sint32 terme) + Point goalCel; // cellule visée (Sint32 terme) + Point passCel; // cellule tranversante + + Sint16 energy; // énergie restante + + Point cel; // cellule actuelle + Point destCel; // cellule destination + Sint16 action; // action en cours + Sint16 aDirect; // direction actuelle + Sint16 sDirect; // direction souhaitée + + Point pos; // position relative à partir de la cellule + Sint16 posZ; // déplacement z + Sint16 channel; + Sint16 lastIcon; + Sint16 icon; + Sint16 phase; // phase dans l'action + Sint16 step; // pas global + Sint16 interrupt; // 0=prioritaire, 1=normal, 2=misc + Sint16 clipLeft; + + Sint32 nbUsed; // nb de points déjà visités + char nextRankUsed; + Point posUsed[MAXUSED]; + char rankUsed[MAXUSED]; + + Sint16 takeChannel; // objet transporté + Sint16 takeIcon; + + Point fix; // point fixe (cultive, pont) + + Sint16 jaugePhase; + Sint16 jaugeMax; + Sint16 stop; // 1 -> devra stopper + Sint16 bArrow; // true -> flèche en dessus de blupi + Sint16 bRepeat; // true -> répète l'action + Sint16 nLoop; // nb de boucles pour GOAL_OTHERLOOP + Sint16 cLoop; // boucle en cours + Sint16 vIcon; // icône variable + Point goalHili; // but visé + Sint16 bMalade; // true -> blupi malade + Sint16 bCache; // true -> caché (pas dessiné) + Sint16 vehicule; // véhicule utilisé par blupi, voir (**) + char busyCount; + char busyDelay; + char clicCount; + char clicDelay; + char reserve2[2]; +} OldBlupi; + +// Sauve le décor sur disque. + +bool +CDecor::Write (Sint32 rank, bool bUser, Sint32 world, Sint32 time, Sint32 total) +{ + std::string filename; + FILE * file = nullptr; + DescFile * pBuffer = nullptr; + Sint32 i; + size_t nb; + + if (bUser) + { + filename = string_format ("data/user%.3d.blp", rank); + AddUserPath (filename); + } + else + { + filename = string_format ("data/world%.3d.blp", rank); + AddUserPath (filename); + } + + file = fopen (filename.c_str (), "wb"); + if (file == nullptr) + goto error; + + pBuffer = (DescFile *) malloc (sizeof (DescFile)); + if (pBuffer == nullptr) + goto error; + memset (pBuffer, 0, sizeof (DescFile)); + + pBuffer->majRev = 1; + pBuffer->minRev = 5; + pBuffer->celCoin = m_celCorner; + pBuffer->world = world; + pBuffer->time = time; + pBuffer->totalTime = total; + pBuffer->term = m_term; + pBuffer->music = m_music; + pBuffer->region = m_region; + pBuffer->skill = m_skill; + pBuffer->nbDecor = MAXCELX * MAXCELY; + pBuffer->lgDecor = sizeof (Cellule); + pBuffer->nbBlupi = MAXBLUPI; + pBuffer->lgBlupi = sizeof (Blupi); + pBuffer->nbMove = MAXMOVE; + pBuffer->lgMove = sizeof (Move); + + for (i = 0; i < MAXBUTTON; i++) + pBuffer->buttonExist[i] = m_buttonExist[i]; + + for (i = 0; i < 4; i++) + pBuffer->memoPos[i] = m_memoPos[i]; + + nb = fwrite (pBuffer, sizeof (DescFile), 1, file); + if (nb < 1) + goto error; + + nb = fwrite (m_decor, sizeof (Cellule), MAXCELX * MAXCELY / 4, file); + if (nb < MAXCELX * MAXCELY / 4) + goto error; + + nb = fwrite (m_blupi, sizeof (Blupi), MAXBLUPI, file); + if (nb < MAXBLUPI) + goto error; + + nb = fwrite (m_move, sizeof (Move), MAXMOVE, file); + if (nb < MAXMOVE) + goto error; + + nb = fwrite (m_lastDrapeau, sizeof (Point), MAXLASTDRAPEAU, file); + if (nb < MAXLASTDRAPEAU) + goto error; + + free (pBuffer); + fclose (file); + return true; + +error: + if (pBuffer != nullptr) + free (pBuffer); + if (file != nullptr) + fclose (file); + return false; +} + +// Lit le décor sur disque. + +bool +CDecor::Read ( + Sint32 rank, bool bUser, Sint32 & world, Sint32 & time, Sint32 & total) +{ + std::string filename; + FILE * file = nullptr; + DescFile * pBuffer = nullptr; + Sint32 majRev, minRev; + Sint32 i, x, y; + size_t nb; + OldBlupi oldBlupi; + + Init (-1, -1); + + if (bUser) + { + filename = string_format ("data/user%.3d.blp", rank); + AddUserPath (filename); + } + else if (rank >= 200) + { + filename = string_format ("data/world%.3d.blp", rank); + AddUserPath (filename); + } + else + filename = string_format (GetBaseDir () + "data/world%.3d.blp", rank); + + file = fopen (filename.c_str (), "rb"); + if (file == nullptr) + goto error; + + pBuffer = (DescFile *) malloc (sizeof (DescFile)); + if (pBuffer == nullptr) + goto error; + + nb = fread (pBuffer, sizeof (DescFile), 1, file); + if (nb < 1) + goto error; + + majRev = pBuffer->majRev; + minRev = pBuffer->minRev; + + if (majRev == 1 && minRev == 0) + goto error; + + if (majRev == 1 && minRev == 3) + { + if ( + pBuffer->nbDecor != MAXCELX * MAXCELY || + pBuffer->lgDecor != sizeof (Cellule) || pBuffer->nbBlupi != MAXBLUPI || + pBuffer->lgBlupi != sizeof (OldBlupi) || pBuffer->nbMove != MAXMOVE || + pBuffer->lgMove != sizeof (Move)) + goto error; + } + else + { + if ( + pBuffer->nbDecor != MAXCELX * MAXCELY || + pBuffer->lgDecor != sizeof (Cellule) || pBuffer->nbBlupi != MAXBLUPI || + pBuffer->lgBlupi != sizeof (Blupi) || pBuffer->nbMove != MAXMOVE || + pBuffer->lgMove != sizeof (Move)) + goto error; + } + + SetCorner (pBuffer->celCoin); + if (bUser) + { + world = pBuffer->world; + time = pBuffer->time; + total = pBuffer->totalTime; + } + m_celHome = pBuffer->celCoin; + m_term = pBuffer->term; + m_music = pBuffer->music; + m_region = pBuffer->region; + + if (bUser) + m_skill = pBuffer->skill; + + for (i = 0; i < MAXBUTTON; i++) + m_buttonExist[i] = pBuffer->buttonExist[i]; + + for (i = 0; i < 4; i++) + m_memoPos[i] = pBuffer->memoPos[i]; + + nb = fread (m_decor, sizeof (Cellule), MAXCELX * MAXCELY / 4, file); + if (nb < MAXCELX * MAXCELY / 4) + goto error; + if (majRev == 1 && minRev < 5) + { + for (x = 0; x < MAXCELX / 2; x++) + { + for (y = 0; y < MAXCELY / 2; y++) + { + if (m_decor[x][y].objectIcon >= 128 && m_decor[x][y].objectIcon <= 130) + m_decor[x][y].objectIcon -= 128 - 17; + } + } + } + + /* Restore the flagged state where flagged ground */ + for (size_t i = 0; i < countof (m_decor); ++i) + for (size_t j = 0; j < countof (m_decor[i]); ++j) + { + if (m_decor[i][j].objectIcon == 124) + m_decorMem[i][j].flagged = true; + } + + if (majRev == 1 && minRev == 3) + { + memset (m_blupi, 0, sizeof (Blupi) * MAXBLUPI); + for (i = 0; i < MAXBLUPI; i++) + { + nb = fread (&oldBlupi, sizeof (OldBlupi), 1, file); + if (nb != 1) + goto error; + memcpy (m_blupi + i, &oldBlupi, sizeof (OldBlupi)); + ListFlush (i); + } + } + else + { + nb = fread (m_blupi, sizeof (Blupi), MAXBLUPI, file); + if (nb < MAXBLUPI) + goto error; + } + + nb = fread (m_move, sizeof (Move), MAXMOVE, file); + if (nb < MAXMOVE) + goto error; + + nb = fread (m_lastDrapeau, sizeof (Point), MAXLASTDRAPEAU, file); + if (nb < MAXLASTDRAPEAU) + InitDrapeau (); + + BlupiDeselect (); // désélectionne tous les blupi + + free (pBuffer); + fclose (file); + return true; + +error: + if (pBuffer != nullptr) + free (pBuffer); + if (file != nullptr) + fclose (file); + + Flush (); // initialise un décor neutre + return false; +} + +// Indique si un fichier existe sur disque. + +bool +CDecor::FileExist ( + Sint32 rank, bool bUser, Sint32 & world, Sint32 & time, Sint32 & total) +{ + std::string filename; + FILE * file = nullptr; + DescFile * pBuffer = nullptr; + Sint32 majRev, minRev; + size_t nb; + + if (bUser) + { + filename = string_format ("data/user%.3d.blp", rank); + AddUserPath (filename); + } + else if (rank >= 200) + { + filename = string_format ("data/world%.3d.blp", rank); + AddUserPath (filename); + } + else + filename = string_format (GetBaseDir () + "data/world%.3d.blp", rank); + + file = fopen (filename.c_str (), "rb"); + if (file == nullptr) + goto error; + + pBuffer = (DescFile *) malloc (sizeof (DescFile)); + if (pBuffer == nullptr) + goto error; + + nb = fread (pBuffer, sizeof (DescFile), 1, file); + if (nb < 1) + goto error; + + majRev = pBuffer->majRev; + minRev = pBuffer->minRev; + + if (majRev == 1 && minRev == 0) + goto error; + + if (majRev == 1 && minRev == 3) + { + if ( + pBuffer->nbDecor != MAXCELX * MAXCELY || + pBuffer->lgDecor != sizeof (Cellule) || pBuffer->nbBlupi != MAXBLUPI || + pBuffer->lgBlupi != sizeof (OldBlupi) || pBuffer->nbMove != MAXMOVE || + pBuffer->lgMove != sizeof (Move)) + goto error; + } + else + { + if ( + pBuffer->nbDecor != MAXCELX * MAXCELY || + pBuffer->lgDecor != sizeof (Cellule) || pBuffer->nbBlupi != MAXBLUPI || + pBuffer->lgBlupi != sizeof (Blupi) || pBuffer->nbMove != MAXMOVE || + pBuffer->lgMove != sizeof (Move)) + goto error; + } + + world = pBuffer->world; + time = pBuffer->time; + total = pBuffer->totalTime; + + free (pBuffer); + fclose (file); + return true; + +error: + if (pBuffer != nullptr) + free (pBuffer); + if (file != nullptr) + fclose (file); + return false; +} + +#define MARG 18 + +// Initialise un décor neutre. + +void +CDecor::Flush () +{ + Sint32 x, y, i, icon; + + Init (-1, -1); + + for (x = 0; x < MAXCELX; x += 2) + { + for (y = 0; y < MAXCELY; y += 2) + { + if (x < MARG || x > MAXCELX - MARG || y < MARG || y > MAXCELY - MARG) + { + icon = 14; // eau + goto put; + } + + if (x == MARG && y == MARG) + { + icon = 12; + goto put; + } + if (x == MAXCELX - MARG && y == MARG) + { + icon = 13; + goto put; + } + if (x == MARG && y == MAXCELY - MARG) + { + icon = 11; + goto put; + } + if (x == MAXCELX - MARG && y == MAXCELY - MARG) + { + icon = 10; + goto put; + } + + if (x == MARG) + { + icon = 4; + goto put; + } + if (x == MAXCELX - MARG) + { + icon = 2; + goto put; + } + if (y == MARG) + { + icon = 5; + goto put; + } + if (y == MAXCELY - MARG) + { + icon = 3; + goto put; + } + + icon = 1; // terre + + put: + m_decor[x / 2][y / 2].floorChannel = CHFLOOR; + m_decor[x / 2][y / 2].floorIcon = icon; + } + } + + for (i = 0; i < MAXBLUPI; i++) + m_blupi[i].bExist = false; + + BlupiCreate (GetCel (102, 100), ACTION_STOP, DIRECT_S, 0, MAXENERGY); + m_decor[98 / 2][100 / 2].floorChannel = CHFLOOR; + m_decor[98 / 2][100 / 2].floorIcon = 16; + m_decor[98 / 2][100 / 2].objectChannel = CHOBJECT; + m_decor[98 / 2][100 / 2].objectIcon = 113; + + for (i = 0; i < MAXBUTTON; i++) + m_buttonExist[i] = 1; + + for (i = 0; i < 4; i++) + { + m_memoPos[i].x = 0; + m_memoPos[i].y = 0; + } + + memset (&m_term, 0, sizeof (Term)); + m_term.bHomeBlupi = true; + m_term.nbMinBlupi = 1; + m_term.nbMaxBlupi = 1; + + m_music = 0; + m_region = 0; + + m_celHome.x = 90; + m_celHome.y = 98; + SetCorner (m_celHome); + InitAfterBuild (); + LoadImages (); +} diff --git a/src/decmap.cxx b/src/decmap.cxx new file mode 100644 index 0000000..1366582 --- /dev/null +++ b/src/decmap.cxx @@ -0,0 +1,595 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "blupi.h" +#include "decor.h" +#include "def.h" + +// clang-format off +#define MAP_CADRE 1 +#define MAP_FOG 2 +#define MAP_BLUPI 3 +#define MAP_SEE 4 +#define MAP_TREE 5 +#define MAP_HERB1 6 +#define MAP_HERB2 7 +#define MAP_TERRE 8 +#define MAP_DALLE 9 +#define MAP_PERSO 10 +#define MAP_NURSE 11 +#define MAP_ROC 12 +#define MAP_MUR 13 +#define MAP_EGG 14 +#define MAP_FIRE 15 +#define MAP_TOMAT 16 +#define MAP_BUILD 17 +#define MAP_ENNEMI 18 +#define MAP_FLEUR 19 +// clang-format on + +#define MAPCADREX ((DIMDRAWX / DIMCELX) * 2 + 1) +#define MAPCADREY (DIMDRAWY / DIMCELY + 1) + +// Bitmap de la carte. + +static Uint32 g_map32_bits[DIMMAPY][DIMMAPX]; + +// Initialise les couleurs pour la carte. + +void +CDecor::MapInitColors () +{ + // FIXME: add big-endian support + const auto MapRGB = [](Uint8 r, Uint8 g, Uint8 b) { + return r << 16 | g << 8 | b << 0; + }; + + m_colors[MAP_CADRE] = MapRGB (255, 0, 0); // rouge + m_colors[MAP_FOG] = MapRGB (0, 0, 0); // noir + m_colors[MAP_BLUPI] = MapRGB (255, 255, 0); // jaune + m_colors[MAP_SEE] = MapRGB (102, 102, 204); // bleu + m_colors[MAP_DALLE] = MapRGB (192, 192, 192); // gris + m_colors[MAP_PERSO] = MapRGB (255, 0, 0); // rouge + m_colors[MAP_NURSE] = MapRGB (255, 0, 0); // rouge + m_colors[MAP_ROC] = MapRGB (214, 214, 214); // gris clair + m_colors[MAP_MUR] = MapRGB (100, 100, 100); // gris moyen + m_colors[MAP_EGG] = MapRGB (255, 255, 255); // blanc + m_colors[MAP_FIRE] = MapRGB (255, 0, 0); // rouge + m_colors[MAP_TOMAT] = MapRGB (255, 0, 0); // rouge + m_colors[MAP_BUILD] = MapRGB (0, 0, 0); // noir + m_colors[MAP_ENNEMI] = MapRGB (0, 192, 255); // bleu métal + m_colors[MAP_FLEUR] = MapRGB (255, 206, 0); // jaune + + m_colors[MAP_TREE] = MapRGB (0, 102, 0); // vert foncé + m_colors[MAP_HERB1] = MapRGB (0, 204, 51); // vert clair + m_colors[MAP_HERB2] = MapRGB (0, 156, 8); // vert moyen + m_colors[MAP_TERRE] = MapRGB (94, 78, 12); // brun + + if (m_region == 1) // palmiers + { + m_colors[MAP_TREE] = MapRGB (38, 197, 42); + m_colors[MAP_HERB1] = MapRGB (184, 140, 1); + m_colors[MAP_HERB2] = MapRGB (145, 110, 5); + m_colors[MAP_TERRE] = MapRGB (192, 192, 192); + } + + if (m_region == 2) // hiver + { + m_colors[MAP_TREE] = MapRGB (152, 205, 222); + m_colors[MAP_HERB1] = MapRGB (219, 234, 239); + m_colors[MAP_HERB2] = MapRGB (223, 173, 90); + m_colors[MAP_TERRE] = MapRGB (152, 205, 222); + } + + if (m_region == 3) // sapins + { + m_colors[MAP_TREE] = MapRGB (0, 102, 0); + m_colors[MAP_HERB1] = MapRGB (38, 197, 42); + m_colors[MAP_HERB2] = MapRGB (140, 140, 0); + m_colors[MAP_TERRE] = MapRGB (172, 178, 173); + } +} + +// COnversion d'un cellule en point dans la carte. + +Point +CDecor::ConvCelToMap (Point cel) +{ + Point pos; + + pos.x = (cel.x - m_celCorner.x) - (cel.y - m_celCorner.y); + pos.y = ((cel.x - m_celCorner.x) + (cel.y - m_celCorner.y)) / 2; + + pos.x += (DIMMAPX - MAPCADREX) / 2; + pos.y += (DIMMAPY - MAPCADREY) / 2; + + return pos; +} + +// Conversion d'un point dans la carte en cellule. + +Point +CDecor::ConvMapToCel (Point pos) +{ + Point cel; + + pos.x -= ((DIMMAPX - MAPCADREX) / 4) * 2; + pos.y -= ((DIMMAPY - MAPCADREY) / 4) * 2; + + cel.x = pos.y + pos.x / 2; + cel.y = pos.y - pos.x / 2; + + cel.x += m_celCorner.x; + cel.y += m_celCorner.y; + + return cel; +} + +// Déplace le décor suite à un clic dans la carte. + +bool +CDecor::MapMove (Point pos) +{ + Point cel; + + if ( + pos.x >= POSMAPX && pos.x < POSMAPX + DIMMAPX && pos.y >= POSMAPY && + pos.y < POSMAPY + DIMMAPY) + { + pos.x -= POSMAPX; + pos.y -= POSMAPY; + cel = ConvMapToCel (pos); + cel.x = cel.x - 10; + cel.y = cel.y; + SetCorner (cel); + NextPhase (0); // faudra refaire la carte tout de suite + return true; + } + + return false; +} + +// clang-format off +static char color_floor[] = +{ + MAP_HERB1, MAP_HERB1, MAP_HERB1, MAP_HERB1, // 0 + MAP_HERB1, MAP_HERB1, MAP_HERB1, MAP_HERB1, + MAP_HERB1, MAP_SEE, MAP_SEE, MAP_SEE, + MAP_SEE, MAP_SEE, MAP_SEE, MAP_HERB1, + MAP_SEE, MAP_SEE, MAP_SEE, MAP_HERB1, + MAP_HERB1, MAP_SEE, MAP_SEE, MAP_SEE, + MAP_HERB1, MAP_SEE, MAP_SEE, MAP_HERB1, + MAP_SEE, MAP_SEE, MAP_HERB1, MAP_HERB1, + MAP_HERB1, MAP_SEE, MAP_SEE, MAP_HERB1, + MAP_HERB1, MAP_HERB1, MAP_SEE, MAP_SEE, + MAP_SEE, MAP_HERB1, MAP_HERB1, MAP_SEE, + MAP_SEE, MAP_SEE, MAP_HERB1, MAP_HERB1, + MAP_SEE, MAP_HERB1, MAP_HERB1, MAP_SEE, + MAP_HERB1, MAP_HERB1, MAP_SEE, MAP_SEE, + MAP_SEE, MAP_SEE, MAP_SEE, MAP_SEE, + MAP_DALLE, MAP_DALLE, MAP_DALLE, MAP_DALLE, + MAP_DALLE, MAP_DALLE, MAP_DALLE, MAP_DALLE, // 16 + MAP_DALLE, MAP_DALLE, MAP_DALLE, MAP_DALLE, + MAP_DALLE, MAP_DALLE, MAP_DALLE, MAP_DALLE, + MAP_DALLE, MAP_DALLE, MAP_DALLE, MAP_DALLE, + MAP_HERB2, MAP_HERB2, MAP_HERB2, MAP_HERB2, + MAP_HERB1, MAP_HERB2, MAP_HERB2, MAP_HERB2, + MAP_HERB2, MAP_HERB2, MAP_HERB2, MAP_HERB1, + MAP_HERB2, MAP_HERB2, MAP_HERB2, MAP_HERB1, + MAP_HERB1, MAP_HERB2, MAP_HERB2, MAP_HERB2, + MAP_HERB2, MAP_HERB2, MAP_HERB2, MAP_HERB1, + MAP_HERB1, MAP_HERB2, MAP_HERB2, MAP_HERB1, + MAP_HERB1, MAP_HERB2, MAP_HERB2, MAP_HERB2, + MAP_HERB1, MAP_HERB2, MAP_HERB2, MAP_HERB1, + MAP_HERB2, MAP_HERB2, MAP_HERB2, MAP_HERB2, + MAP_HERB1, MAP_HERB2, MAP_HERB2, MAP_HERB2, + MAP_HERB2, MAP_HERB2, MAP_HERB2, MAP_HERB2, + MAP_HERB2, MAP_HERB2, MAP_HERB2, MAP_HERB1, // 32 + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_HERB1, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_HERB1, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_HERB1, + MAP_HERB1, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_HERB1, + MAP_HERB1, MAP_TERRE, MAP_TERRE, MAP_HERB1, + MAP_HERB1, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_HERB1, MAP_TERRE, MAP_TERRE, MAP_HERB1, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_HERB1, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_HERB1, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, // 48 + MAP_HERB1, MAP_HERB1, MAP_HERB1, MAP_HERB1, + MAP_HERB1, MAP_HERB1, MAP_HERB1, MAP_HERB1, + MAP_HERB1, MAP_HERB1, MAP_HERB1, MAP_HERB1, + MAP_NURSE, MAP_NURSE, MAP_NURSE, MAP_NURSE, + MAP_NURSE, MAP_NURSE, MAP_NURSE, MAP_NURSE, + MAP_NURSE, MAP_NURSE, MAP_NURSE, MAP_NURSE, + MAP_NURSE, MAP_NURSE, MAP_NURSE, MAP_NURSE, + MAP_NURSE, MAP_NURSE, MAP_NURSE, MAP_NURSE, + MAP_HERB1, MAP_HERB1, MAP_HERB1, MAP_HERB1, + MAP_HERB1, MAP_HERB1, MAP_HERB1, MAP_HERB1, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, // 64 + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, + MAP_SEE, MAP_SEE, MAP_SEE, MAP_SEE, + MAP_SEE, MAP_SEE, MAP_SEE, MAP_SEE, + MAP_SEE, MAP_SEE, MAP_SEE, MAP_SEE, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, +}; + +static char color_object[] = +{ + 0, MAP_TREE, 0, MAP_TREE, + MAP_TREE, 0, MAP_TREE, 0, + 0, MAP_TREE, 0, MAP_TREE, + MAP_TREE, MAP_TREE, MAP_TREE, MAP_TREE, + MAP_TREE, MAP_TREE, MAP_TREE, MAP_TREE, + MAP_TREE, MAP_TREE, MAP_TREE, MAP_TREE, + + 0, MAP_TREE, 0, MAP_TREE, // arbre + MAP_TREE, 0, MAP_TREE, 0, + 0, MAP_TREE, 0, MAP_TREE, + MAP_TREE, MAP_TREE, MAP_TREE, MAP_TREE, + MAP_TREE, MAP_TREE, MAP_TREE, MAP_TREE, + MAP_TREE, MAP_TREE, MAP_TREE, MAP_TREE, + + 0, MAP_TREE, 0, MAP_TREE, // sapin + MAP_TREE, 0, MAP_TREE, 0, + 0, MAP_TREE, 0, MAP_TREE, + MAP_TREE, MAP_TREE, MAP_TREE, MAP_TREE, + MAP_TREE, MAP_TREE, MAP_TREE, MAP_TREE, + MAP_TREE, MAP_TREE, MAP_TREE, MAP_TREE, + + MAP_TREE, MAP_TREE, MAP_TREE, MAP_TREE, // palmiers + MAP_TREE, MAP_TREE, MAP_TREE, MAP_TREE, + + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, // mur + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, + + MAP_BUILD, MAP_BUILD, MAP_BUILD, MAP_BUILD, // maison + MAP_BUILD, MAP_BUILD, MAP_BUILD, MAP_BUILD, + + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, // arbre sans feuille + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, + + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, // planches + + MAP_ROC, MAP_ROC, MAP_ROC, MAP_ROC, // rochers + MAP_ROC, MAP_ROC, MAP_ROC, MAP_ROC, + MAP_ROC, MAP_ROC, MAP_ROC, MAP_ROC, + MAP_ROC, MAP_ROC, MAP_ROC, MAP_ROC, + MAP_ROC, MAP_ROC, MAP_ROC, MAP_ROC, + MAP_ROC, MAP_ROC, MAP_ROC, MAP_ROC, + MAP_ROC, MAP_ROC, MAP_ROC, MAP_ROC, + MAP_ROC, MAP_ROC, MAP_ROC, MAP_ROC, // pierres + + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, // feu + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, // test + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, + + MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, // tomates + MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, + MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, + MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, + + MAP_BUILD, MAP_BUILD, MAP_BUILD, MAP_BUILD, // cabane + MAP_BUILD, MAP_BUILD, MAP_BUILD, MAP_BUILD, + + MAP_EGG, MAP_EGG, MAP_EGG, MAP_EGG, // oeufs + MAP_EGG, MAP_EGG, MAP_EGG, MAP_EGG, + + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, // palissade + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, + + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, // pont construction + MAP_MUR, MAP_MUR, MAP_MUR, MAP_MUR, + + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, // rayon + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, // bouteille + + MAP_FLEUR, MAP_FLEUR, MAP_FLEUR, MAP_FLEUR, // fleurs + MAP_FLEUR, MAP_FLEUR, MAP_FLEUR, MAP_FLEUR, + MAP_FLEUR, MAP_FLEUR, MAP_FLEUR, MAP_FLEUR, + MAP_FLEUR, MAP_FLEUR, MAP_FLEUR, MAP_FLEUR, + + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, // dynamite + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + MAP_FIRE, MAP_FIRE, MAP_FIRE, MAP_FIRE, + + MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, // poison + MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, + + MAP_FLEUR, MAP_FLEUR, MAP_FLEUR, MAP_FLEUR, + MAP_FLEUR, MAP_FLEUR, MAP_FLEUR, MAP_FLEUR, + + MAP_HERB1, MAP_HERB1, MAP_HERB1, MAP_HERB1, // ennemi piégé + MAP_HERB1, MAP_HERB1, MAP_HERB1, MAP_HERB1, + MAP_HERB1, MAP_HERB1, MAP_HERB1, MAP_HERB1, + + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, // usine + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, + + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, // barrière + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, + + MAP_BUILD, MAP_BUILD, MAP_BUILD, MAP_BUILD, // maison + MAP_HERB1, MAP_HERB1, MAP_HERB1, MAP_HERB1, // ennemi piégé + + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, + MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, MAP_ENNEMI, + + MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, // bateau + MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, // jeep + + MAP_BUILD, MAP_BUILD, MAP_BUILD, MAP_BUILD, // usine + MAP_BUILD, MAP_BUILD, MAP_BUILD, MAP_BUILD, + MAP_BUILD, MAP_BUILD, MAP_BUILD, MAP_BUILD, // mine de fer + MAP_BUILD, MAP_BUILD, MAP_BUILD, MAP_BUILD, + + MAP_TERRE, MAP_TERRE, MAP_TERRE, MAP_TERRE, // fer + MAP_EGG, MAP_EGG, MAP_EGG, MAP_EGG, // drapeau + MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, // mine + MAP_BUILD, MAP_BUILD, MAP_BUILD, MAP_BUILD, + MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, MAP_TOMAT, // mine +}; +// clang-format on + +static char color_deffog[4] = { + MAP_FOG, + MAP_FOG, + MAP_FOG, + MAP_FOG, +}; + +static char color_deftree[4] = { + MAP_TREE, + MAP_TREE, + MAP_TREE, + MAP_TREE, +}; + +static char color_deffloor[4] = { + MAP_HERB1, + MAP_HERB1, + MAP_HERB1, + MAP_HERB1, +}; + +static char color_fire[4] = { + MAP_FIRE, + MAP_FIRE, + MAP_FIRE, + MAP_FIRE, +}; + +// Met le contenu d'une cellule dans le bitmap de la carte +// (sol, objets et brouillard). + +void +CDecor::MapPutCel (Point pos) +{ + Point cel, fogCel; + Sint32 icon, i; + char * pColors; + + cel = ConvMapToCel (pos); + cel.x = (cel.x / 2) * 2; + cel.y = (cel.y / 2) * 2; + + if (!IsValid (cel)) + { + pColors = color_deffog; + goto color; + } + + if (m_bFog) + { + // fogPos.x = (pos.x/4)*4; + // fogPos.y = (pos.y/4)*4; + // fogCel = ConvMapToCel(fogPos); + fogCel = cel; + fogCel.x = (fogCel.x / 4) * 4; + fogCel.y = (fogCel.y / 4) * 4; + if ( + fogCel.x < 0 || fogCel.x >= MAXCELX || fogCel.y < 0 || + fogCel.y >= MAXCELY || + m_decor[fogCel.x / 2][fogCel.y / 2].fog == FOGHIDE) // caché ? + { + pColors = color_deffog; + goto color; + } + } + + icon = m_decor[cel.x / 2][cel.y / 2].objectIcon; + if (icon != -1) + { + if ( + m_decor[cel.x / 2][cel.y / 2].fire > 0 && + m_decor[cel.x / 2][cel.y / 2].fire < MoveMaxFire ()) + { + pColors = color_fire; + goto color; + } + + if (icon >= 0 && icon <= 127) + pColors = color_object + 4 * (icon - 0); + else + pColors = color_deftree; + goto color; + } + + icon = m_decor[cel.x / 2][cel.y / 2].floorIcon; + if (icon >= 0 && icon <= 71) + pColors = color_floor + 4 * (icon - 0); + else + pColors = color_deffloor; + +color: + for (i = 0; i < 4; i++) + { + if (pos.x + i >= 0 && pos.x + i < DIMMAPX) + { + icon = *pColors++; + if (icon != 0) + g_map32_bits[pos.y][pos.x + i] = m_colors[icon]; + } + } +} + +// Génère la carte. + +bool +CDecor::GenerateMap () +{ + Point pos, cel; + Sint32 dx, rank, i; + + auto DrawMap = [&]() -> bool { + if (!m_SurfaceMap) + return true; + + Point dim = {DIMMAPX, DIMMAPY}; + m_pPixmap->Cache (CHMAP, m_SurfaceMap, dim); + + Point pos = {POSMAPX, POSMAPY}; + m_pPixmap->DrawIcon (-1, CHMAP, 0, pos); + + return true; + }; + + if (m_phase != -1 && m_phase % 2 != 0) + return DrawMap (); + + // Dessine le décor (sol, objets et brouillard). + for (pos.y = 0; pos.y < DIMMAPY; pos.y++) + { + dx = pos.y % 2; + for (pos.x = -dx * 2; pos.x < DIMMAPX; pos.x += 4) + MapPutCel (pos); + } + + // Dessine les blupi. + for (rank = 0; rank < MAXBLUPI; rank++) + { + if (m_blupi[rank].bExist) + { + pos = ConvCelToMap (m_blupi[rank].cel); + + if (this->GetSkill () >= 1 && !m_bBuild) + { + auto fogCel = m_blupi[rank].cel; + fogCel.x = (fogCel.x / 4) * 4; + fogCel.y = (fogCel.y / 4) * 4; + if (m_decor[fogCel.x / 2][fogCel.y / 2].fog == FOGHIDE) // hidden? + continue; + } + + if ( + pos.x >= 0 && pos.x < DIMMAPX - 1 && pos.y >= 0 && pos.y < DIMMAPY - 1) + { + if (m_blupi[rank].perso == 0 || m_blupi[rank].perso == 8) + i = MAP_BLUPI; + else + i = MAP_PERSO; + + g_map32_bits[pos.y + 0][pos.x + 0] = m_colors[i]; + g_map32_bits[pos.y + 0][pos.x + 1] = m_colors[i]; + g_map32_bits[pos.y + 1][pos.x + 0] = m_colors[i]; + g_map32_bits[pos.y + 1][pos.x + 1] = m_colors[i]; + } + } + } + + // Dessine le cadre. + cel = m_celCorner; + pos = ConvCelToMap (cel); + + for (i = pos.x; i < pos.x + MAPCADREX; i++) + { + g_map32_bits[pos.y][i] = m_colors[MAP_CADRE]; + g_map32_bits[pos.y + MAPCADREY][i] = m_colors[MAP_CADRE]; + } + for (i = pos.y; i <= pos.y + MAPCADREY; i++) + { + g_map32_bits[i][pos.x] = m_colors[MAP_CADRE]; + g_map32_bits[i][pos.x + MAPCADREX] = m_colors[MAP_CADRE]; + } + + if (m_SurfaceMap) + SDL_FreeSurface (m_SurfaceMap); + + m_SurfaceMap = SDL_CreateRGBSurfaceFrom ( + g_map32_bits, DIMMAPX, DIMMAPY, 32, 4 * DIMMAPX, 0, 0, 0, 0); + return DrawMap (); +} diff --git a/src/decmove.cxx b/src/decmove.cxx new file mode 100644 index 0000000..df62fff --- /dev/null +++ b/src/decmove.cxx @@ -0,0 +1,1446 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "decmove.h" +#include "decor.h" +#include "misc.h" + +// clang-format off +/** + * Movements to shake a tree + * (synchronized with ACTION_PIOCHE). + */ +static Sint16 table_move1[] = +{ + 9 * 4, // nb + 0, 0, + 0, 0, + 0, 0, + 0, 0, + -2, 0, + +2, 0, + -1, 0, + +1, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + -2, 0, + +2, 0, + -1, 0, + +1, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + -2, 0, + +2, 0, + -1, 0, + +1, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + -2, 0, + +2, 0, + -1, 0, + +1, 0, +}; + +/** + * Movements to jump an object (east) on Blupi + * (synchronized with ACTION_TAKE). + */ +static Sint16 table_move2[] = +{ + 9 + 19, // nb + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, -10, + 0, -20, + 0, -30, + 0, -40, + -1, -50, + -3, -60, + -7, -70, + -15, -80, + -22, -70, + -30, -56, + -30, -56, + -30, -56, + -30, -56, + -30, -56, + -30, -56, + -30, -56, + -30, -56, + -30, -56, + -30, -56, +}; + +/** + * Movements to jump an object (south) on Blupi + * (synchronized with ACTION_TAKE2). + */ +static Sint16 table_move3[] = +{ + 9 + 19, // nb + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, -10, + 0, -20, + 0, -30, + 0, -40, + 1, -50, + 3, -60, + 7, -70, + 15, -80, + 22, -70, + 30, -56, + 30, -56, + 30, -56, + 30, -56, + 30, -56, + 30, -56, + 30, -56, + 30, -56, + 30, -56, + 30, -56, +}; + +/** + * Movements to drop and object (east) on Blupi + * (synchronized with ACTION_DEPOSE). + */ +static Sint16 table_move4[] = +{ + 10, // nb + -30, -60, + -22, -70, + -15, -80, + -7, -70, + -3, -60, + -1, -50, + 0, -40, + 0, -30, + 0, -20, + 0, -10, +}; + +/** + * Movements to drop an object (south) on Blupi + * (synchronized with ACTION_DEPOSE2). + */ +static Sint16 table_move5[] = +{ + 10, // nb + 30, -60, + 22, -70, + 15, -80, + 7, -70, + 3, -60, + 1, -50, + 0, -40, + 0, -30, + 0, -20, + 0, -10, +}; + +/** + * Movements to push a bridge to the east. + */ +static Sint16 table_move6[] = +{ + 40, // nb + +2, +1, + +4, +2, + +6, +3, + +8, +4, + +10, +5, + +12, +6, + +14, +7, + +16, +8, + +18, +9, + +20, +10, + +22, +11, + +24, +12, + +26, +13, + +28, +14, + +30, +15, + +32, +16, + +34, +17, + +36, +18, + +38, +19, + +40, +20, + +42, +21, + +44, +22, + +46, +23, + +48, +24, + +50, +25, + +52, +26, + +54, +27, + +56, +28, + +58, +29, + +60, +30, + +60, +30, + +60, +30, + +60, +30, + +60, +30, + +60, +30, + +60, +30, + +60, +30, + +60, +30, + +60, +30, + +60, +30, +}; + +/** + * Movements to push a bridge to the west. + */ +static Sint16 table_move7[] = +{ + 40, // nb + -2, -1, + -4, -2, + -6, -3, + -8, -4, + -10, -5, + -12, -6, + -14, -7, + -16, -8, + -18, -9, + -20, -10, + -22, -11, + -24, -12, + -26, -13, + -28, -14, + -30, -15, + -32, -16, + -34, -17, + -36, -18, + -38, -19, + -40, -20, + -42, -21, + -44, -22, + -46, -23, + -48, -24, + -50, -25, + -52, -26, + -54, -27, + -56, -28, + -58, -29, + -60, -30, + -60, -30, + -60, -30, + -60, -30, + -60, -30, + -60, -30, + -60, -30, + -60, -30, + -60, -30, + -60, -30, + -60, -30, +}; + +/** + * Movements to push a bridge to the south. + */ +static Sint16 table_move8[] = +{ + 40, // nb + -2, +1, + -4, +2, + -6, +3, + -8, +4, + -10, +5, + -12, +6, + -14, +7, + -16, +8, + -18, +9, + -20, +10, + -22, +11, + -24, +12, + -26, +13, + -28, +14, + -30, +15, + -32, +16, + -34, +17, + -36, +18, + -38, +19, + -40, +20, + -42, +21, + -44, +22, + -46, +23, + -48, +24, + -50, +25, + -52, +26, + -54, +27, + -56, +28, + -58, +29, + -60, +30, + -60, +30, + -60, +30, + -60, +30, + -60, +30, + -60, +30, + -60, +30, + -60, +30, + -60, +30, + -60, +30, + -60, +30, +}; + +/** + * Movements to push a bridge to the north. + */ +static Sint16 table_move9[] = +{ + 40, // nb + +2, -1, + +4, -2, + +6, -3, + +8, -4, + +10, -5, + +12, -6, + +14, -7, + +16, -8, + +18, -9, + +20, -10, + +22, -11, + +24, -12, + +26, -13, + +28, -14, + +30, -15, + +32, -16, + +34, -17, + +36, -18, + +38, -19, + +40, -20, + +42, -21, + +44, -22, + +46, -23, + +48, -24, + +50, -25, + +52, -26, + +54, -27, + +56, -28, + +58, -29, + +60, -30, + +60, -30, + +60, -30, + +60, -30, + +60, -30, + +60, -30, + +60, -30, + +60, -30, + +60, -30, + +60, -30, + +60, -30, +}; + +/** + * Movements to shake a laboratory. + */ +static Sint16 table_move10[] = +{ + 16 * 4, // nb + -2, 0, + +2, 0, + -2, 0, + +2, 0, + -2, 0, + +2, 0, + -2, 0, + +2, 0, + -2, 0, + +2, 0, + -2, 0, + +2, 0, + -2, 0, + +2, 0, + -2, 0, + +2, 0, + -1, 0, + +1, 0, + -1, 0, + +1, 0, + -1, 0, + +1, 0, + -1, 0, + +1, 0, + -1, 0, + +1, 0, + -1, 0, + +1, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + -2, 0, + +2, 0, + -2, 0, + +2, 0, + -2, 0, + +2, 0, + -2, 0, + +2, 0, + -2, 0, + +2, 0, + -2, 0, + +2, 0, + -2, 0, + +2, 0, + -2, 0, + +2, 0, + -1, 0, + +1, 0, + -1, 0, + +1, 0, + -1, 0, + +1, 0, + -1, 0, + +1, 0, + -1, 0, + +1, 0, + -1, 0, + +1, 0, +}; + +/** + * Movements to shake a mine. + */ +static Sint16 table_move11[] = +{ + 20 * 4, // nb + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + 0, -1, + 0, +1, +}; + +/** + * Movements to shake a factory. + */ +static Sint16 table_move12[] = +{ + 20 * 4, // nb + -1, 0, + +1, 0, + -1, 0, + +1, 0, + 0, -1, + 0, +1, + 0, -1, + 0, +1, + -1, 0, + +1, 0, + -1, 0, + +1, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + -2, 0, + +2, 0, + 0, +1, + 0, +1, + -2, 0, + +2, 0, + 0, +1, + 0, +1, + -1, 0, + +1, 0, + -1, 0, + +1, 0, + -2, 0, + +2, 0, + 0, +1, + 0, +1, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + -1, 0, + +1, 0, + -1, 0, + +1, 0, + -1, 0, + +1, 0, + -1, 0, + +1, 0, + 0, -1, + 0, +1, + 0, -2, + 0, +2, + -1, 0, + +1, 0, + -1, 0, + +1, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + -1, 0, + +1, 0, + -1, 0, + +1, 0, + -2, 0, + +2, 0, + 0, +1, + 0, +1, + -2, 0, + +2, 0, + 0, +1, + 0, +1, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + -2, 0, + +2, 0, + 0, +1, + 0, +1, +}; +// clang-format on + +Sint16 * +GetListMoves (Sint32 rank) +{ + switch (rank) + { + case 1: + return table_move1; + case 2: + return table_move2; + case 3: + return table_move3; + case 4: + return table_move4; + case 5: + return table_move5; + case 6: + return table_move6; + case 7: + return table_move7; + case 8: + return table_move8; + case 9: + return table_move9; + case 10: + return table_move10; + case 11: + return table_move11; + case 12: + return table_move12; + } + + return nullptr; +} + +// clang-format off +/** + * Small fire. + */ +static Sint16 table_icon1[] = +{ + 8 * 3, + 49, 50, 51, 52, 50, 49, 51, 52, + 49, 52, 51, 50, 49, 52, 50, 49, + 52, 51, 50, 49, 51, 52, 49, 51, +}; + +/** + * Large fire. + */ +static Sint16 table_icon2[] = +{ + 8 * 3, + 45, 46, 47, 48, 46, 45, 48, 47, + 46, 45, 48, 47, 45, 48, 47, 48, + 46, 45, 48, 47, 45, 48, 47, 46, +}; + +// Eclairs de la dalle nurserie. +static Sint16 table_icon3[] = +{ + 4, // nb + 53, 54, 55, 56, +}; + +// Eclairs n-s entre les tours. +static Sint16 table_icon4[] = +{ + 8 * 4, // nb + 74, 76, 78, 76, 74, 78, 74, 76, + 78, 76, 74, 76, 74, 76, 78, 76, + 74, 78, 76, 74, 76, 78, 74, 76, + 78, 74, 76, 78, 74, 76, 74, 78, +}; + +// Eclairs e-o entre les tours. +static Sint16 table_icon5[] = +{ + 8 * 4, // nb + 75, 77, 75, 79, 75, 77, 79, 75, + 79, 77, 75, 77, 75, 79, 75, 79, + 75, 77, 79, 75, 75, 77, 79, 75, + 79, 75, 77, 79, 75, 79, 75, 79, +}; + +// Explosion de la dynamite. +static Sint16 table_icon6[] = +{ + 7 + 30, // nb + 91, 90, 89, 88, 89, 90, 91, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +// Mèche de la dynamite. +static Sint16 table_icon7[] = +{ + 12 * 4, // nb + 86, 87, 86, 87, 86, 87, 86, 87, 86, 87, 86, 87, + 86, 87, 86, 87, 86, 87, 86, 87, 86, 87, 86, 87, + 86, 87, 86, 87, 86, 87, 86, 87, 86, 87, 86, 87, + 86, 87, 86, 87, 86, 87, 86, 87, 86, 87, 86, 87, +}; + +// Rayons de l'électrocuteur. +static Sint16 table_icon8[] = +{ + 10 * 10, // nb + 75, -1, -1, 74, -1, 75, -1, 74, 75, -1, + 74, 73, -1, 75, 74, 73, 72, 74, -1, 72, + 73, 74, 72, 73, 75, 73, 72, 73, 74, 72, + 75, 72, 73, 72, -1, 74, 73, 72, 75, 74, + -1, 73, 74, 75, -1, 74, 75, -1, 75, -1, + 74, 75, -1, -1, 74, -1, -1, -1, 75, -1, + -1, -1, -1, -1, -1, 74, -1, -1, -1, 75, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 75, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 74, +}; + +// Blupi écrasé. +static Sint16 table_icon9[] = +{ + 10 * 10, // nb + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, +}; + +// Blupi malade écrasé. +static Sint16 table_icon10[] = +{ + 10 * 10, // nb + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, +}; + +// Eclairs de la dalle téléporteur. +static Sint16 table_icon11[] = +{ + 4, // nb + 81, 82, 83, 84, +}; +// clang-format on + +Sint16 * +GetListIcons (Sint32 rank) +{ + switch (rank) + { + case 1: + return table_icon1; + case 2: + return table_icon2; + case 3: + return table_icon3; + case 4: + return table_icon4; + case 5: + return table_icon5; + case 6: + return table_icon6; + case 7: + return table_icon7; + case 8: + return table_icon8; + case 9: + return table_icon9; + case 10: + return table_icon10; + case 11: + return table_icon11; + } + + return nullptr; +} + +/** + * \brief Remove all animated environments. + */ +void +CDecor::MoveFlush () +{ + Sint32 i, x, y; + + for (i = 0; i < MAXMOVE; i++) + m_move[i].bExist = false; + + for (x = 0; x < MAXCELX / 2; x++) + { + for (y = 0; y < MAXCELY / 2; y++) + m_decor[x][y].rankMove = -1; + } +} + +/** + * \brief Get the fire duration. + * + * \returns the duration. + */ +Sint32 +CDecor::MoveMaxFire () +{ + if (m_skill >= 1) + return (MAXFIRE / 4) * 3; + return MAXFIRE; +} + +/** + * \brief Initialize all environment perpetual movements. + */ +void +CDecor::MoveFixInit () +{ + Sint32 x, y; + + MoveFlush (); + + for (x = 0; x < MAXCELX; x += 2) + { + for (y = 0; y < MAXCELY; y += 2) + { + // Démarre le feu. + if ( + m_decor[x / 2][y / 2].fire > 0 && + m_decor[x / 2][y / 2].fire < MoveMaxFire ()) + MoveStartFire (GetCel (x, y)); + + // Démarre les éclairs entre les tours. + if (m_decor[x / 2][y / 2].objectIcon == 10000) // éclair n-s + { + if (MoveCreate ( + GetCel (x, y), -1, false, CHOBJECT, -1, -1, -1, 9999, 1, 0, true)) + { + MoveAddIcons (GetCel (x, y), 4, true); // éclairs n-s + } + } + + if (m_decor[x / 2][y / 2].objectIcon == 10001) // éclair e-o + { + if (MoveCreate ( + GetCel (x, y), -1, false, CHOBJECT, -1, -1, -1, 9999, 1, 0, true)) + { + MoveAddIcons (GetCel (x, y), 5, true); // éclairs e-o + } + } + } + } +} + +/** + * \brief Create a new animated environment. + * + * If \p bMisc is true, we keep 10 movements back for important + * actions (\p bMisc == false). + * + * \param[in] cel - ? + * \param[in] rankBlupi - ? + * \param[in] bFloor - ? + * \param[in] channel - ? + * \param[in] icon - ? + * \param[in] maskChannel - ? + * \param[in] maskIcon - ? + * \param[in] total - ? + * \param[in] delai - ? + * \param[in] stepY - ? + * \param[in] bMisc - ? + * \param[in] bNotIfExist - ? + * \returns true on success. + */ +bool +CDecor::MoveCreate ( + Point cel, Sint32 rankBlupi, bool bFloor, Sint32 channel, Sint32 icon, + Sint32 maskChannel, Sint32 maskIcon, Sint32 total, Sint32 delai, Sint32 stepY, + bool bMisc, bool bNotIfExist) +{ + Sint32 rank, max; + + for (rank = 0; rank < MAXMOVE; rank++) + { + if ( + m_move[rank].bExist && m_move[rank].cel.x == cel.x && + m_move[rank].cel.y == cel.y) + { + if (bNotIfExist) + return false; + goto create; + } + } + + max = 0; + for (rank = 0; rank < MAXMOVE; rank++) + { + if (!m_move[rank].bExist) + { + if (bMisc && max > MAXMOVE - 10) + return false; + goto create; + } + max++; + } + return false; + +create: + m_move[rank].bExist = true; + m_move[rank].cel = cel; + m_move[rank].rankBlupi = rankBlupi; + m_move[rank].bFloor = bFloor; + m_move[rank].channel = channel; + m_move[rank].icon = icon; + m_move[rank].maskChannel = maskChannel; + m_move[rank].maskIcon = maskIcon; + m_move[rank].total = total; + m_move[rank].delai = delai; + m_move[rank].stepY = stepY; + m_move[rank].cTotal = 0; + m_move[rank].cDelai = 0; + m_move[rank].rankMoves = 0; + m_move[rank].rankIcons = 0; + m_move[rank].phase = 0; + + m_decor[cel.x / 2][cel.y / 2].rankMove = rank; + return true; +} + +// Ajoute un mouvement. + +bool +CDecor::MoveAddMoves (Point cel, Sint32 rankMoves) +{ + Sint32 rank; + + for (rank = 0; rank < MAXMOVE; rank++) + { + if ( + m_move[rank].bExist && m_move[rank].cel.x == cel.x && + m_move[rank].cel.y == cel.y) + { + m_move[rank].rankMoves = rankMoves; + m_move[rank].phase = 0; + + return true; + } + } + + return false; +} + +// Ajoute un mouvement. + +bool +CDecor::MoveAddIcons (Point cel, Sint32 rankIcons, bool bContinue) +{ + Sint32 rank; + + for (rank = 0; rank < MAXMOVE; rank++) + { + if ( + m_move[rank].bExist && m_move[rank].cel.x == cel.x && + m_move[rank].cel.y == cel.y) + { + m_move[rank].rankIcons = rankIcons; + if (!bContinue) + m_move[rank].phase = 0; + + if (rankIcons == 4 || rankIcons == 5) // éclairs entre tours ? + m_move[rank].cTotal = Random (0, 10); + + return true; + } + } + + return false; +} + +/** + * \brief Test if something can burn at a specified cell. + * + * \param[in] cel - Position. + * \returns true if possible. + */ +bool +CDecor::CanBurn (Point cel) +{ + Sint32 channel, icon; + bool canBurn = false; + + cel.x = (cel.x / 2) * 2; + cel.y = (cel.y / 2) * 2; + + const auto cell = m_decor[cel.x / 2][cel.y / 2]; + + channel = cell.objectChannel; + icon = cell.objectIcon; + + canBurn = channel == CHOBJECT && ((icon >= 6 && icon <= 11) // trees ? + || (icon >= 65 && icon <= 71) // palissade ? + || icon == 61 // cabane ? + || icon == 36 // planches ? + || icon == 60 // tomatoes ? + || icon == 63 // eggs ? + || icon == 113 // house ? + || icon == 121 // mine de fer ? + || icon == 122 // mine de fer ? + ); + if (canBurn) + return true; + + // If there is an other object, then no fire. + if (channel >= 0) + return false; + + channel = cell.floorChannel; + icon = cell.floorIcon; + + canBurn = channel == CHFLOOR && (icon == 20 || // herbe foncée ? + (icon >= 59 && icon <= 64)); + return canBurn; +} + +/** + * \brief Start the fire on a cell. + * + * \param[in] cel - Position. + * \returns true if possible. + */ +bool +CDecor::MoveStartFire (Point cel) +{ + if (this->CanBurn (cel)) + { + cel.x = (cel.x / 2) * 2; + cel.y = (cel.y / 2) * 2; + + if (!MoveCreate (cel, -1, false, CHOBJECT, -1, -1, -1, 9999, 1, 0, true)) + return false; + + MoveAddIcons (cel, 1, true); // small fire + m_decor[cel.x / 2][cel.y / 2].fire = 2; + return true; + } + + return false; +} + +// Démarre le feu si c'est possible par proximité. + +void +CDecor::MoveProxiFire (Point cel) +{ + Sint32 cx, cy, xx, yy, x, y, channel, icon; + + static Sint16 tableInd[5] = {2, 1, 3, 0, 4}; + // clang-format off + static Sint16 tablePos[5 * 5 * 2] = + { + 0, 0, -1, -2, 0, -2, +1, -2, 0, 0, + -2, -1, -1, -1, 0, -1, +1, -1, +2, -1, + -2, 0, -1, 0, 0, 0, +1, 0, +2, 0, + -2, +1, -1, +1, 0, +1, +1, +1, +2, +1, + 0, 0, -1, +2, 0, +2, +1, +2, 0, 0, + }; + // clang-format on + + for (cx = 0; cx < 5; cx++) + { + for (cy = 0; cy < 5; cy++) + { + xx = tablePos[(tableInd[cx] + tableInd[cy] * 5) * 2 + 0]; + yy = tablePos[(tableInd[cx] + tableInd[cy] * 5) * 2 + 1]; + + if (xx == 0 && yy == 0) + continue; + + x = cel.x + xx * 2; + y = cel.y + yy * 2; + + if (x < 0 || x >= MAXCELX || y < 0 || y >= MAXCELX) + continue; + + if (m_decor[x / 2][y / 2].fire != 0) + continue; // brule déjà ? + + x = ((cel.x + xx) / 2) * 2; + y = ((cel.y + yy) / 2) * 2; + + // Mur ou rochers entre le feu et l'objet ? + channel = m_decor[x / 2][y / 2].objectChannel; + icon = m_decor[x / 2][y / 2].objectIcon; + if ( + channel == CHOBJECT && + ((icon >= 20 && icon <= 26) || (icon >= 37 && icon <= 43))) + continue; + + x = cel.x + xx * 2; + y = cel.y + yy * 2; + + // Mur ou rochers entre le feu et l'objet ? + channel = m_decor[x / 2][y / 2].objectChannel; + icon = m_decor[x / 2][y / 2].objectIcon; + if ( + channel == CHOBJECT && + ((icon >= 20 && icon <= 26) || (icon >= 37 && icon <= 43))) + continue; + + // Démarre éventuellement un seul foyer. + if (MoveStartFire (GetCel (x, y))) + return; + } + } +} + +// Fait évoluer le feu. + +void +CDecor::MoveFire (Sint32 rank) +{ + Sint32 x, y, icon, newIcon; + Point pos; + + x = (m_move[rank].cel.x / 2) * 2; + y = (m_move[rank].cel.y / 2) * 2; + + if ( + m_decor[x / 2][y / 2].fire == 0 || + m_decor[x / 2][y / 2].fire >= MoveMaxFire ()) + return; + + m_decor[x / 2][y / 2].fire++; + + pos = ConvCelToPos (GetCel (x, y)); + m_pSound->PlayImage (SOUND_FIRE, pos); + + if (m_decor[x / 2][y / 2].objectIcon >= 0) // objet qui brule ? + { + if ( + m_decor[x / 2][y / 2].fire > MoveMaxFire () / 2 && + m_decor[x / 2][y / 2].fire % 50 == 0) // pas trop souvent ! + { + MoveProxiFire (GetCel (x, y)); // boutte le feu + } + + // Début petites flammes. + if (m_decor[x / 2][y / 2].fire == 2) + MoveStartFire (GetCel (x, y)); + + // Début grandes flammes. + if (m_decor[x / 2][y / 2].fire == (MoveMaxFire () - DIMOBJY * 2) / 2) + { + MoveAddIcons (GetCel (x, y), 2, true); // grandes flammes + } + + // Début objet squelette. + if (m_decor[x / 2][y / 2].fire == MoveMaxFire () - DIMOBJY * 2) + { + icon = m_decor[x / 2][y / 2].floorIcon; + if (icon == 20) // herbe foncée ? + { + PutFloor (GetCel (x, y), CHFLOOR, 19); // herbe brulée + } + + icon = m_decor[x / 2][y / 2].objectIcon; + newIcon = -1; + if (icon >= 6 && icon <= 11) + newIcon = icon - 6 + 30; // arbres ? + if (icon == 61) + newIcon = 62; // cabane ? + if (icon == 113) + newIcon = 15; // maison ? + if (icon == 121) + newIcon = 126; // mine de fer ? + if (icon == 122) + newIcon = 126; // mine de fer ? + MoveCreate ( + GetCel (x, y), -1, false, CHOBJECT, newIcon, -1, -1, DIMOBJY * 2, 1, + -1 * 50); + MoveAddIcons (GetCel (x, y), 2, true); // grandes flammes + } + + // Fin grandes flammes. + if (m_decor[x / 2][y / 2].fire == MoveMaxFire () - DIMOBJY) + { + MoveAddIcons (GetCel (x, y), 1, true); // petites flammes + } + + // Fin feu. + if (m_decor[x / 2][y / 2].fire == MoveMaxFire () - 1) + { + MoveFinish (GetCel (x, y)); + icon = m_decor[x / 2][y / 2].objectIcon; + if ( + icon == 36 || // planches ? + icon == 60 || // tomates ? + icon == 63 || // oeufs ? + icon == 113 || // maison ? + (icon >= 65 && icon <= 71)) // palissade ? + { + m_decor[x / 2][y / 2].objectChannel = -1; + m_decor[x / 2][y / 2].objectIcon = -1; + } + m_decor[x / 2][y / 2].fire = MoveMaxFire (); // déjà brulé + } + } + else // sol qui brule ? + { + if ( + m_decor[x / 2][y / 2].fire > DIMOBJY && + m_decor[x / 2][y / 2].fire % 50 == 0) // pas trop souvent ! + { + MoveProxiFire (GetCel (x, y)); // boutte le feu + } + + // Début petites flammes. + if (m_decor[x / 2][y / 2].fire == 2) + MoveStartFire (GetCel (x, y)); + + // Milieu feu. + if (m_decor[x / 2][y / 2].fire == DIMOBJY) + { + icon = m_decor[x / 2][y / 2].floorIcon; + switch (icon) + { + case 20: // herbe foncée ? + PutFloor (GetCel (x, y), CHFLOOR, 19); // herbe brulée + break; + case 59: // pont ? + PutFloor (GetCel (x, y), CHFLOOR, 2); // rivage + break; + case 61: // pont ? + PutFloor (GetCel (x, y), CHFLOOR, 4); // rivage + break; + case 62: // pont ? + PutFloor (GetCel (x, y), CHFLOOR, 3); // rivage + break; + case 64: // pont ? + PutFloor (GetCel (x, y), CHFLOOR, 5); // rivage + break; + case 60: + case 63: // pont ? + PutFloor (GetCel (x, y), CHFLOOR, 14); // eau + break; + } + } + + // Fin feu. + if (m_decor[x / 2][y / 2].fire == DIMOBJY * 2 - 1) + { + MoveFinish (GetCel (x, y)); + m_decor[x / 2][y / 2].objectChannel = -1; + m_decor[x / 2][y / 2].objectIcon = -1; + m_decor[x / 2][y / 2].fire = MoveMaxFire (); // déjà brulé + } + } +} + +// Fait évoluer tous les décors animés. + +void +CDecor::MoveStep (bool bFirst) +{ + Sint32 rank, rankBlupi; + + for (rank = 0; rank < MAXMOVE; rank++) + { + if (m_move[rank].bExist) + { + if ( + !bFirst && (m_move[rank].rankIcons == 4 || // éclair entre tours ? + m_move[rank].rankIcons == 5)) + continue; + + MoveFire (rank); + + // Si le blupi travaillant ici est stoppé, on + // arrête aussi la construction. + rankBlupi = m_move[rank].rankBlupi; + if (rankBlupi != -1) + { + if ( + m_blupi[rankBlupi].action == ACTION_STOP || + m_blupi[rankBlupi].action == ACTION_STOPTIRED) + continue; + } + + m_move[rank].phase++; + if (m_move[rank].phase > 32000) + m_move[rank].phase = 0; + + m_move[rank].cDelai++; + if (m_move[rank].cDelai >= m_move[rank].delai) // délai écoulé ? + { + m_move[rank].cDelai = 0; + + m_move[rank].cTotal++; + if (m_move[rank].cTotal > 32000) + m_move[rank].cTotal = 0; + + if ( + m_move[rank].total != 9999 && + m_move[rank].cTotal >= m_move[rank].total) + MoveFinish (m_move[rank].cel); + } + } + } +} + +// Termine un mouvement pour une cellule donnée. + +void +CDecor::MoveFinish (Point cel) +{ + Sint32 rank; + + for (rank = 0; rank < MAXMOVE; rank++) + { + if ( + m_move[rank].bExist && m_move[rank].cel.x == cel.x && + m_move[rank].cel.y == cel.y) + { + if (m_move[rank].channel >= 0 && m_move[rank].icon >= 0) + { + if (m_move[rank].bFloor) + PutFloor (cel, m_move[rank].channel, m_move[rank].icon); + else + PutObject (cel, m_move[rank].channel, m_move[rank].icon); + } + + m_decor[cel.x / 2][cel.y / 2].rankMove = -1; + m_move[rank].bExist = false; + } + } +} + +// Termine un mouvement, d'après le rang du blupi. + +void +CDecor::MoveFinish (Sint32 rankBlupi) +{ + Sint32 rank; + + for (rank = 0; rank < MAXMOVE; rank++) + { + if (m_move[rank].bExist && m_move[rank].rankBlupi == rankBlupi) + MoveFinish (m_move[rank].cel); + } +} + +// Vérifie si une cellule est déjà utilisée. + +bool +CDecor::MoveIsUsed (Point cel) +{ + Sint32 rank; + + for (rank = 0; rank < MAXMOVE; rank++) + { + if ( + m_move[rank].bExist && m_move[rank].cel.x == cel.x && + m_move[rank].cel.y == cel.y) + return true; + } + + return false; +} + +// Retourne l'objet en construction à un endroit donné. + +bool +CDecor::MoveGetObject (Point cel, Sint32 & channel, Sint32 & icon) +{ + Sint32 rank; + + for (rank = 0; rank < MAXMOVE; rank++) + { + if ( + m_move[rank].bExist && m_move[rank].cel.x == cel.x && + m_move[rank].cel.y == cel.y && m_move[rank].bFloor == false) + { + channel = m_move[rank].channel; + icon = m_move[rank].icon; + return true; + } + } + + return false; +} + +// Modifie un objet en construction à un endroit donné. + +bool +CDecor::MovePutObject (Point cel, Sint32 channel, Sint32 icon) +{ + Sint32 rank; + + for (rank = 0; rank < MAXMOVE; rank++) + { + if ( + m_move[rank].bExist && m_move[rank].cel.x == cel.x && + m_move[rank].cel.y == cel.y && m_move[rank].bFloor == false) + { + m_move[rank].channel = channel; + m_move[rank].icon = icon; + return true; + } + } + + return false; +} diff --git a/src/decmove.h b/src/decmove.h new file mode 100644 index 0000000..9ed92f2 --- /dev/null +++ b/src/decmove.h @@ -0,0 +1,26 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include + +Sint16 * GetListMoves (Sint32 rank); +Sint16 * GetListIcons (Sint32 rank); diff --git a/src/decor.cxx b/src/decor.cxx new file mode 100644 index 0000000..a6ba4b6 --- /dev/null +++ b/src/decor.cxx @@ -0,0 +1,3509 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include +#include +#include + +#include "action.h" +#include "decmove.h" +#include "decor.h" +#include "def.h" +#include "fifo.h" +#include "gettext.h" +#include "misc.h" +#include "pixmap.h" +#include "sound.h" +#include "text.h" + +#define TEXTDELAY 10 // délai avant apparition tooltips + +Point +GetCel (Sint32 x, Sint32 y) +{ + Point cel; + + cel.x = x; + cel.y = y; + + return cel; +} + +Point +GetCel (Point cel, Sint32 x, Sint32 y) +{ + cel.x += x; + cel.y += y; + + return cel; +} + +// Indique si une coordonnée de cellule est valide. +// On ne peut pas aller dans la dernière cellule tout au +// bord (-2) pour permettre de gérer le brouillard proprement +// jusque dans les bords ! + +bool +IsValid (Point cel) +{ + if (cel.x < 2 || cel.x >= MAXCELX - 2 || cel.y < 2 || cel.y >= MAXCELX - 2) + return false; + return true; +} + +// Retourne un vecteur orienté dans une direction donnée. + +Point +GetVector (Sint32 direct) +{ + Point vector; + + vector.x = 0; + vector.y = 0; + + switch (direct) + { + case DIRECT_E: + vector.x = +1; + break; + case DIRECT_SE: + vector.x = +1; + vector.y = +1; + break; + case DIRECT_S: + vector.y = +1; + break; + case DIRECT_SW: + vector.x = -1; + vector.y = +1; + break; + case DIRECT_W: + vector.x = -1; + break; + case DIRECT_NW: + vector.x = -1; + vector.y = -1; + break; + case DIRECT_N: + vector.y = -1; + break; + case DIRECT_NE: + vector.x = +1; + vector.y = -1; + break; + } + return vector; +} + +// Constructeur. + +CDecor::CDecor () +{ + m_pSound = nullptr; + m_pUndoDecor = nullptr; + + m_celCorner.x = 90; + m_celCorner.y = 98; + + m_celHili.x = -1; + m_celOutline1.x = -1; + m_celOutline2.x = -1; + + m_bHiliRect = false; // pas de rectangle de sélection + m_shiftHili = 0; + + m_shiftOffset.x = 0; + m_shiftOffset.y = 0; + + m_nbBlupiHili = 0; + m_rankBlupiHili = -1; + m_rankHili = -1; + + m_bFog = false; + m_bBuild = false; + m_bInvincible = false; + m_bSuper = false; + m_bHideTooltips = false; + m_bInfo = false; + m_infoHeight = 100; + m_phase = 0; + m_totalTime = 0; + m_region = 0; + m_lastRegion = 999; + m_skill = 0; + m_SurfaceMap = nullptr; + + Init (CHFLOOR, 0); + BlupiFlush (); + MoveFlush (); + InitDrapeau (); +} + +// Destructeur. + +CDecor::~CDecor () +{ + if (m_SurfaceMap) + SDL_FreeSurface (m_SurfaceMap); + + UndoClose (); // libère le buffer du undo +} + +// Initialisation générale. + +void +CDecor::Create (CSound * pSound, CPixmap * pPixmap) +{ + m_pSound = pSound; + m_pPixmap = pPixmap; + m_bOutline = false; +} + +// Initialise le décor avec un sol plat partout. + +void +CDecor::Init (Sint32 channel, Sint32 icon) +{ + Sint32 x, y; + + for (x = 0; x < MAXCELX / 2; x++) + { + for (y = 0; y < MAXCELY / 2; y++) + { + m_decor[x][y].floorChannel = channel; + m_decor[x][y].floorIcon = icon; + + m_decor[x][y].objectChannel = -1; + m_decor[x][y].objectIcon = -1; + + m_decor[x][y].fog = FOGHIDE; // caché + m_decor[x][y].rankMove = -1; + m_decor[x][y].workBlupi = -1; + m_decor[x][y].fire = 0; + m_decorMem[x][y].flagged = false; + } + } + + for (x = 0; x < MAXCELX; x++) + { + for (y = 0; y < MAXCELY; y++) + m_rankBlupi[x][y] = -1; + } + + m_bOutline = false; + m_bGroundRedraw = true; +} + +// Initialise le décor après une modification. + +void +CDecor::InitAfterBuild () +{ + ClearFog (); // met tout sous le brouillard + ClearFire (); + MoveFixInit (); + InitDrapeau (); + BlupiDeselect (); +} + +// Initialise les mises en évidence, avant de jouer. + +void +CDecor::ResetHili () +{ + m_bHiliRect = false; // plus de rectangle + InitOutlineRect (); +} + +// Charge les images nécessaires au décor. + +bool +CDecor::LoadImages () +{ + Point totalDim, iconDim; + char filename[50]; + + if (m_region == m_lastRegion) + return true; + m_lastRegion = m_region; + + totalDim.x = DIMCELX * 2 * 16; + totalDim.y = DIMCELY * 2 * 6; + iconDim.x = DIMCELX * 2; + iconDim.y = DIMCELY * 2; + snprintf (filename, sizeof (filename), "floor%.3d.png", m_region); + if (!m_pPixmap->Cache (CHFLOOR, filename, totalDim, iconDim)) + return false; + + totalDim.x = DIMOBJX * 16; + totalDim.y = DIMOBJY * 8; + iconDim.x = DIMOBJX; + iconDim.y = DIMOBJY; + snprintf (filename, sizeof (filename), "obj%.3d.png", m_region); + if (!m_pPixmap->Cache (CHOBJECT, filename, totalDim, iconDim)) + return false; + + snprintf (filename, sizeof (filename), "obj-o%.3d.png", m_region); + if (!m_pPixmap->Cache (CHOBJECTo, filename, totalDim, iconDim)) + return false; + + MapInitColors (); // init les couleurs pour la carte + + m_bGroundRedraw = true; + return true; +} + +// Met partout du brouillard, sauf aux endroits des blupi. + +void +CDecor::ClearFog () +{ + Sint32 x, y, rank; + + for (x = 0; x < MAXCELX / 2; x++) + { + for (y = 0; y < MAXCELY / 2; y++) + { + m_decor[x][y].fog = FOGHIDE; // caché + } + } + + for (rank = 0; rank < MAXBLUPI; rank++) + { + if (m_blupi[rank].bExist) + BlupiPushFog (rank); + } + + m_bOutline = false; +} + +// Permet de nouveau aux cellules brulées de bruler. + +void +CDecor::ClearFire () +{ + Sint32 x, y; + + for (x = 0; x < MAXCELX / 2; x++) + { + for (y = 0; y < MAXCELY / 2; y++) + { + if (m_decor[x][y].fire >= MoveMaxFire ()) // déjà brulé ? + { + m_decor[x][y].fire = 0; // pourra de nouveau bruler + } + + if (m_decor[x][y].fire > 1) // en train de bruler ? + { + m_decor[x][y].fire = 1; // début du feu + } + } + } +} + +// Indique le mode jeu/construction. + +void +CDecor::SetBuild (bool bBuild) +{ + m_bBuild = bBuild; +} + +// Indique s'il faut tenir compte du brouillard. + +void +CDecor::EnableFog (bool bEnable) +{ + m_bFog = bEnable; + m_bOutline = false; +} + +// Gestion du mode invincible. + +bool +CDecor::GetInvincible () +{ + return m_bInvincible; +} + +void +CDecor::SetInvincible (bool bInvincible) +{ + m_bInvincible = bInvincible; +} + +// Gestion du mode costaud (superblupi). + +bool +CDecor::GetSuper () +{ + return m_bSuper; +} + +void +CDecor::SetSuper (bool bSuper) +{ + m_bSuper = bSuper; +} + +// Bascule le mode outline. + +void +CDecor::FlipOutline () +{ + m_bOutline = !m_bOutline; + m_timeFlipOutline = m_timeConst + 50; +} + +// Initialise un sol dans une cellule. + +bool +CDecor::PutFloor (Point cel, Sint32 channel, Sint32 icon) +{ + if (cel.x < 0 || cel.x >= MAXCELX || cel.y < 0 || cel.y >= MAXCELY) + return false; + + m_decor[cel.x / 2][cel.y / 2].floorChannel = channel; + m_decor[cel.x / 2][cel.y / 2].floorIcon = icon; + + m_bGroundRedraw = true; + + //? SubDrapeau(cel); // on pourra de nouveau planter un drapeau + + return true; +} + +// Initialise un objet dans une cellule. + +bool +CDecor::PutObject (Point cel, Sint32 channel, Sint32 icon) +{ + if (cel.x < 0 || cel.x >= MAXCELX || cel.y < 0 || cel.y >= MAXCELY) + return false; + + if (icon == -1) + channel = -1; + + m_decor[cel.x / 2][cel.y / 2].objectChannel = channel; + m_decor[cel.x / 2][cel.y / 2].objectIcon = icon; + + /* When flagged, it's possible to build a mine for iron */ + if (icon == 124) + m_decorMem[cel.x / 2][cel.y / 2].flagged = true; + + SubDrapeau (cel); // on pourra de nouveau planter un drapeau + + return true; +} + +// Retourne un sol dans une cellule. + +bool +CDecor::GetFloor (Point cel, Sint32 & channel, Sint32 & icon) +{ + if (cel.x < 0 || cel.x >= MAXCELX || cel.y < 0 || cel.y >= MAXCELY) + return false; + + channel = m_decor[cel.x / 2][cel.y / 2].floorChannel; + icon = m_decor[cel.x / 2][cel.y / 2].floorIcon; + + return true; +} + +// Retourne une objet dans une cellule. + +bool +CDecor::GetObject (Point cel, Sint32 & channel, Sint32 & icon) +{ + if (cel.x < 0 || cel.x >= MAXCELX || cel.y < 0 || cel.y >= MAXCELY) + return false; + + channel = m_decor[cel.x / 2][cel.y / 2].objectChannel; + icon = m_decor[cel.x / 2][cel.y / 2].objectIcon; + + return true; +} + +// Modifie le feu pour une cellule. + +bool +CDecor::SetFire (Point cel, bool bFire) +{ + if (cel.x < 0 || cel.x >= MAXCELX || cel.y < 0 || cel.y >= MAXCELY) + return false; + + m_decor[cel.x / 2][cel.y / 2].fire = bFire ? 1 : 0; + + return true; +} + +void +CDecor::FixShifting (Sint32 & nbx, Sint32 & nby, Point & iCel, Point & iPos) +{ + if (m_shiftOffset.x < 0) // décalage à droite ? + nbx += 2; + if (m_shiftOffset.y < 0) // décalage en bas ? + nby += 3; + if (m_shiftOffset.x > 0) // décalage à gauche ? + { + nbx += 2; + iCel.x--; + iCel.y++; + iPos = ConvCelToPos (iCel); + } + if (m_shiftOffset.y > 0) // décalage en haut ? + { + nby += 2; + iCel.x--; + iCel.y--; + iPos = ConvCelToPos (iCel); + } +} + +// Modifie l'offset pour le shift. + +void +CDecor::SetShiftOffset (Point offset) +{ + m_shiftOffset = offset; + m_bGroundRedraw = true; +} + +// Convertit la position d'une cellule en coordonnée graphique. + +Point +CDecor::ConvCelToPos (Point cel) +{ + Point pos; + + pos.x = ((cel.x - m_celCorner.x) - (cel.y - m_celCorner.y)) * (DIMCELX / 2); + pos.y = ((cel.x - m_celCorner.x) + (cel.y - m_celCorner.y)) * (DIMCELY / 2); + + pos.x += POSDRAWX + m_shiftOffset.x; + pos.y += POSDRAWY + m_shiftOffset.y; + + return pos; +} + +// Convertit une coordonnée graphique en cellule. + +Point +CDecor::ConvPosToCel (Point pos, bool bMap) +{ + Point cel; + + if ( + bMap && pos.x >= POSMAPX && pos.x < POSMAPX + DIMMAPX && pos.y >= POSMAPY && + pos.y < POSMAPY + DIMMAPY) + { + pos.x -= POSMAPX; + pos.y -= POSMAPY; + return ConvMapToCel (pos); + } + + pos.x -= POSDRAWX + DIMCELX / 2; + pos.y -= POSDRAWY; + + cel.x = (pos.y * DIMCELX + pos.x * DIMCELY) / (DIMCELX * DIMCELY); + // cel.y = (pos.y*DIMCELX - pos.x*DIMCELY) / (DIMCELX*DIMCELY); + cel.y = (pos.y * DIMCELX - pos.x * DIMCELY); + if (cel.y < 0) + cel.y -= (DIMCELX * DIMCELY); + cel.y /= (DIMCELX * DIMCELY); + + cel.x += m_celCorner.x; + cel.y += m_celCorner.y; + + return cel; +} + +// Convertit une coordonnée graphique en grande cellule (2x2). + +Point +CDecor::ConvPosToCel2 (Point pos) +{ + Point cel; + + pos.x -= POSDRAWX + DIMCELX / 2; + pos.y -= POSDRAWY; + + if (m_celCorner.x % 2 != 0 && m_celCorner.y % 2 == 0) + { + pos.x += DIMCELX / 2; + pos.y += DIMCELY / 2; + } + + if (m_celCorner.x % 2 == 0 && m_celCorner.y % 2 != 0) + { + pos.x -= DIMCELX / 2; + pos.y += DIMCELY / 2; + } + + if (m_celCorner.x % 2 != 0 && m_celCorner.y % 2 != 0) + pos.y += DIMCELY; + + cel.x = + (pos.y * DIMCELX * 2 + pos.x * DIMCELY * 2) / (DIMCELX * 2 * DIMCELY * 2); + // cel.y = (pos.y*DIMCELX*2 - pos.x*DIMCELY*2) / (DIMCELX*2*DIMCELY*2); + cel.y = (pos.y * DIMCELX * 2 - pos.x * DIMCELY * 2); + if (cel.y < 0) + cel.y -= (DIMCELX * 2 * DIMCELY * 2); + cel.y /= (DIMCELX * 2 * DIMCELY * 2); + + cel.x = (cel.x * 2 + m_celCorner.x) / 2 * 2; + cel.y = (cel.y * 2 + m_celCorner.y) / 2 * 2; + + return cel; +} + +// Attribution des blupi aux différentes cellules. +// Lorsque un blupi a deux positions (courante et destination), +// il faut toujours mettre blupi le plus au fond possible +// (minimiser x et y). + +void +CDecor::BuildPutBlupi () +{ + Sint32 x, y, dx, dy, xMin, yMin, rank, clipLeft; + Point pos; + + for (rank = 0; rank < MAXBLUPI; rank++) + { + if ( + m_blupi[rank].bExist && m_blupi[rank].channel != -1 && + m_blupi[rank].icon != -1) + { + xMin = m_blupi[rank].destCel.x; + if (xMin > m_blupi[rank].cel.x) + xMin = m_blupi[rank].cel.x; + yMin = m_blupi[rank].destCel.y; + if (yMin > m_blupi[rank].cel.y) + yMin = m_blupi[rank].cel.y; + + // Si blupi entre dans une maison, il faut initialiser + // le clipping à gauche. + m_blupi[rank].clipLeft = 0; // pas de clipping + + if ( + !m_bOutline && xMin > 0 && xMin % 2 == 1 && yMin % 2 == 1 && + m_decor[xMin / 2][yMin / 2].objectChannel == CHOBJECT && + (m_decor[xMin / 2][yMin / 2].objectIcon == 28 || // maison ? + m_decor[xMin / 2][yMin / 2].objectIcon == 101 || // usine ? + m_decor[xMin / 2][yMin / 2].objectIcon == 103 || // usine ? + m_decor[xMin / 2][yMin / 2].objectIcon == 105 || // usine ? + m_decor[xMin / 2][yMin / 2].objectIcon == 116 || // usine ? + m_decor[xMin / 2][yMin / 2].objectIcon == 120 || // usine ? + m_decor[xMin / 2][yMin / 2].objectIcon == 18 || // usine ? + m_decor[xMin / 2][yMin / 2].objectIcon == 122 || // mine ? + m_decor[xMin / 2][yMin / 2].objectIcon == 113) && // maison ? + m_blupi[rank].posZ > -DIMBLUPIY) + { + pos = ConvCelToPos (GetCel (xMin, yMin)); + clipLeft = pos.x + 34; + if (clipLeft < POSDRAWX) + clipLeft = POSDRAWX; + m_blupi[rank].clipLeft = clipLeft; + } + + x = m_blupi[rank].cel.x; + y = m_blupi[rank].cel.y; + + dx = m_blupi[rank].destCel.x - x; + dy = m_blupi[rank].destCel.y - y; + + if (dx != -dy) // déplacement non horizontal (ne/so) ? + { + if (dx < 0) + x = m_blupi[rank].destCel.x; + if (dy < 0) + y = m_blupi[rank].destCel.y; + } + if (dx == -1 && dy == 1) // déplacement "so" ? + { + x = m_blupi[rank].destCel.x; + y = m_blupi[rank].destCel.y; + } + + if (x % 2 != 0) + { + if ( + IsFreeCelObstacle (GetCel (x, y + 0)) && + !IsFreeCelObstacle (GetCel (x, y + 1))) + x--; + } + + if (x % 2 == 0 && y % 2 != 0) + { + if (!IsFreeCelObstacle (GetCel (x + 1, y))) + y--; + } + + if (x % 2 != 0 && y % 2 != 0 && dx != 0 && dy == 0) + { + if (!IsFreeCelObstacle (GetCel (x + 1, y - 1))) + x++; + } + + if (m_rankBlupi[x][y] != -1) // déjà occupé ? + { + if (x == m_blupi[rank].cel.x) + x--; + else + x = m_blupi[rank].cel.x; + + if (m_rankBlupi[x][y] != -1) // déjà occupé ? + { + if (y == m_blupi[rank].cel.y) + y--; + else + y = m_blupi[rank].cel.y; + + if (m_rankBlupi[x][y] != -1) // déjà occupé ? + { + /* HACK: It's not right but at least less Blupi are + * lost (invisible). The logic is not very clear, then + * consider the following code as a workaround. + */ + if (x == m_blupi[rank].cel.x) + x -= 2; + else + x = m_blupi[rank].cel.x; + + if (m_rankBlupi[x][y] != -1) + continue; // que faire d'autre ? + } + } + } + m_rankBlupi[x][y] = rank; + } + } +} + +// Dessine une cellule du décor contenant un sol animé. + +void +CDecor::BuildMoveFloor (Sint32 x, Sint32 y, Point pos, Sint32 rank) +{ + Sint32 icon, nb; + Sint16 * pTable; + + if (m_move[rank].rankIcons == 0) + { + icon = m_move[rank].maskIcon + m_move[rank].cTotal; + + m_pPixmap->BuildIconMask ( + m_move[rank].maskChannel, icon, m_move[rank].channel, m_move[rank].icon, + 0); + + m_pPixmap->DrawIcon (-1, m_move[rank].channel, 0, pos); + } + else + { + pTable = GetListIcons (m_move[rank].rankIcons); + nb = pTable[0]; + icon = pTable[1 + m_move[rank].cTotal % nb]; + + if (m_move[rank].cel.x % 2 == 1) + { + pos.x += DIMCELX / 2; + pos.y += DIMCELY / 2; + } + if (m_move[rank].cel.y % 2 == 1) + { + pos.x -= DIMCELX / 2; + pos.y += DIMCELY / 2; + } + + m_pPixmap->DrawIcon (-1, m_move[rank].channel, icon, pos); + } +} + +// Dessine une cellule du décor contenant un objet animé. + +void +CDecor::BuildMoveObject (Sint32 x, Sint32 y, Point pos, Sint32 rank) +{ + Sint32 hBuild, offset, startY, endY; + Sint32 channel, icon, nb; + Sint16 * pTable; + + if (m_move[rank].rankMoves != 0) + { + pTable = GetListMoves (m_move[rank].rankMoves); + offset = m_move[rank].phase; + if (offset < pTable[0]) + { + pos.x += pTable[1 + 2 * offset + 0]; + pos.y += pTable[1 + 2 * offset + 1]; + } + else + m_move[rank].rankMoves = 0; + } + + // Dessine un chiffre par-dessus + if (m_move[rank].icon >= MOVEICONNB && m_move[rank].icon <= MOVEICONNB + 100) + { + Point textPos; + char string[20]; + + m_pPixmap->DrawIcon ( + -1, m_decor[x / 2][y / 2].objectChannel, m_decor[x / 2][y / 2].objectIcon, + pos); + snprintf (string, sizeof (string), "%d", m_move[rank].icon - MOVEICONNB); + textPos.x = pos.x + DIMCELX / 2 + 32; + textPos.y = pos.y + (DIMOBJY - DIMCELY * 2) + 36; + DrawTextCenter (m_pPixmap, textPos, string, FONTLITTLE); + } + else + { + hBuild = (m_move[rank].cTotal * m_move[rank].stepY) / 100; + if (m_move[rank].stepY >= 0) + { + if (hBuild <= 0) + hBuild = 0; + if (hBuild > DIMOBJY) + hBuild = DIMOBJY; + } + else + { + if (hBuild >= 0) + hBuild = 0; + if (hBuild < -DIMOBJY) + hBuild = -DIMOBJY; + } + + // Dessine l'objet actuellement dans le décor. + if (m_decor[x / 2][y / 2].objectChannel >= 0) + { + if (hBuild >= 0) + { + startY = 0; + endY = DIMOBJY - hBuild; + } + else + { + startY = -hBuild; + endY = DIMOBJY; + } + + channel = m_decor[x / 2][y / 2].objectChannel; + if (m_bOutline && channel == CHOBJECT) + channel = CHOBJECTo; + + m_pPixmap->DrawIconPart ( + -1, channel, m_decor[x / 2][y / 2].objectIcon, pos, startY, endY); + } + + // Dessine le nouvel objet par-dessus. + if (m_move[rank].icon >= 0) + { + if (hBuild >= 0) + { + startY = DIMOBJY - hBuild; + endY = DIMOBJY; + } + else + { + startY = 0; + endY = -hBuild; + } + + channel = m_move[rank].channel; + if (m_bOutline && channel == CHOBJECT) + channel = CHOBJECTo; + + m_pPixmap->DrawIconPart ( + -1, channel, m_move[rank].icon, pos, startY, endY); + } + } + + // Dessine le feu ou les rayons. + if (m_move[rank].rankIcons != 0) + { + pTable = GetListIcons (m_move[rank].rankIcons); + nb = pTable[0]; + icon = pTable[1 + m_move[rank].cTotal % nb]; + + m_pPixmap->DrawIcon (-1, m_move[rank].channel, icon, pos); + } +} + +// Déplace l'objet transporté par blupi. + +void +BuildMoveTransport (Sint32 icon, Point & pos) +{ + pos.x -= DIMCELX / 2; + pos.y -= 96; + + // clang-format off + static Sint32 offset_bateau[16 * 2] = + { + -4, -3, // e + -2, -3, + -1, -3, // se + +1, -3, + +2, -3, // s + +5, -2, + +6, -2, // so + +5, -1, + +1, 0, // o + -1, 0, + -2, 0, // no + -2, 0, + -3, 0, // n + -4, -1, + -5, -1, // ne + -4, -2, + }; + + static Sint32 offset_jeep[16 * 2] = + { + -2, -6, // e + -1, -6, + -1, -6, // se + -1, -6, + +3, -6, // s + +1, -6, + +4, -6, // so + +4, -5, + +4, -5, // o + +2, -5, + +1, -4, // no + +1, -4, + -3, -3, // n + -4, -4, + -3, -4, // ne + -4, -4, + }; + // clang-format on + + if (icon >= 0 && icon <= 47) + pos.y -= (icon % 3) * 2; + + if (icon == 114) // mange ? + { + pos.x += 1; + pos.y += 1; + } + + if (icon == 106) // se penche (mèche dynamite) ? + { + pos.x += 8; + pos.y += 10; + } + + if (icon == 194) // se penche (mèche dynamite) ? + { + pos.x += 9; + pos.y += 9; + } + + if (icon == 347) // se penche (armure) ? + { + pos.x += 2; + pos.y += 2; + } + + if (icon >= 234 && icon <= 249) // blupi en bateau ? + { + pos.x += offset_bateau[(icon - 234) * 2 + 0]; + pos.y += offset_bateau[(icon - 234) * 2 + 1]; + } + + if (icon >= 250 && icon <= 265) // blupi en jeep ? + { + pos.x += offset_jeep[(icon - 250) * 2 + 0]; + pos.y += offset_jeep[(icon - 250) * 2 + 1]; + } + + if (icon == 270) + pos.y += 3; // blupi électrocuté + if (icon == 271) + pos.y -= 2; + if (icon == 272) + pos.y -= 7; +} + +// Construit tous les sols fixes dans CHGROUND. + +void +CDecor::BuildGround (Rect clip) +{ + //? OutputDebug("BuildGround\n"); + Sint32 x, y, i, j, nbx, nby, width, height, channel, icon; + Point iCel, mCel, iPos, mPos, cPos, pos; + + width = clip.right - clip.left; + height = clip.bottom - clip.top; + + pos.x = clip.left; + pos.y = clip.top; + iCel = ConvPosToCel (pos); + mCel = iCel; + + if (mCel.x % 2 == 0 && mCel.y % 2 == 0) + { + iCel.x -= 2; + width += DIMCELX; + height += DIMCELY; + } + + if (mCel.x % 2 != 0 && mCel.y % 2 != 0) + { + iCel.x -= 3; + iCel.y -= 1; + width += DIMCELX; + height += DIMCELY * 2; + } + + if (mCel.x % 2 == 0 && mCel.y % 2 != 0) + { + iCel.x -= 2; + iCel.y -= 1; + width += DIMCELX / 2; + height += (DIMCELY / 2) * 3; + } + + if (mCel.x % 2 != 0 && mCel.y % 2 == 0) + { + iCel.x -= 3; + width += (DIMCELX / 2) * 3; + height += (DIMCELY / 2) * 3; + } + + iPos = ConvCelToPos (iCel); + + nbx = (width / DIMCELX) + 2; + nby = (height / (DIMCELY / 2)) + 0; + + if (GetInfoHeight () != 0) + { + nbx += 2; + nby += 2; + } + + this->FixShifting (nbx, nby, iCel, iPos); + + // Construit les sols. + mCel = iCel; + mPos = iPos; + for (j = 0; j < nby; j++) + { + x = mCel.x; + y = mCel.y; + cPos = mPos; + for (i = 0; i < nbx; i++) + { + if (x % 2 == 0 && y % 2 == 0) + { + pos.x = cPos.x - DIMCELX / 2; + pos.y = cPos.y; + + if ( + x >= 2 && x < MAXCELX - 2 && y >= 2 && y < MAXCELY - 2 && + m_decor[x / 2][y / 2].floorChannel >= 0 && + m_decor[x / 2][y / 2].floorIcon >= 0) + { + channel = m_decor[x / 2][y / 2].floorChannel; + icon = m_decor[x / 2][y / 2].floorIcon; + } + else + { + channel = CHFLOOR; + icon = 78; // losange noir + } + + if (!m_bBuild && icon == 71) // terre à fer ? + { + icon = 33; // terre normale ! + } + + // Dessine l'eau sous les rives et les ponts. + if ( + (icon >= 2 && icon <= 13) || // rive ? + (icon >= 59 && icon <= 64)) // pont ? + { + m_pPixmap->DrawIcon (CHGROUND, CHFLOOR, 14, pos); // eau + } + + m_pPixmap->DrawIcon (CHGROUND, channel, icon, pos); + } + + x++; + y--; + cPos.x += DIMCELX; + } + + if (j % 2 == 0) + { + mCel.y++; + mPos.x -= DIMCELX / 2; + mPos.y += DIMCELY / 2; + } + else + { + mCel.x++; + mPos.x += DIMCELX / 2; + mPos.y += DIMCELY / 2; + } + } + + m_bGroundRedraw = false; +} + +// Construit le décor dans un pixmap. + +void +CDecor::Build (Rect clip, Point posMouse) +{ + Sint32 x, y, i, j, nbx, nby, width, height, rank, icon, channel, n; + Point iCel, mCel, cel, iPos, mPos, cPos, pos, tPos; + Rect oldClip, clipRect; + + static Sint32 table_eau[6] = {70, 68, 14, 69, 14, 68}; + static Sint32 table_random_x[10] = {2, 5, 1, 9, 4, 0, 6, 3, 8, 7}; + static Sint32 table_random_y[10] = {4, 8, 3, 5, 9, 1, 7, 2, 0, 6}; + + oldClip = m_pPixmap->GetClipping (); + m_pPixmap->SetClipping (clip); + + if (m_bGroundRedraw) + { + BuildGround (clip); // refait les sols fixes + } + + // Dessine tous les sols fixes. + m_pPixmap->DrawImage (-1, CHGROUND, clip); + + width = clip.right - clip.left; + height = clip.bottom - clip.top; + + pos.x = clip.left; + pos.y = clip.top; + iCel = ConvPosToCel (pos); + mCel = iCel; + + if (mCel.x % 2 == 0 && mCel.y % 2 == 0) + { + iCel.x -= 2; + width += DIMCELX; + height += DIMCELY; + } + + if (mCel.x % 2 != 0 && mCel.y % 2 != 0) + { + iCel.x -= 3; + iCel.y -= 1; + width += DIMCELX; + height += DIMCELY * 2; + } + + if (mCel.x % 2 == 0 && mCel.y % 2 != 0) + { + iCel.x -= 2; + iCel.y -= 1; + width += DIMCELX / 2; + height += (DIMCELY / 2) * 3; + } + + if (mCel.x % 2 != 0 && mCel.y % 2 == 0) + { + iCel.x -= 3; + width += (DIMCELX / 2) * 3; + height += (DIMCELY / 2) * 3; + } + + iPos = ConvCelToPos (iCel); + + nbx = (width / DIMCELX) + 2; + nby = (height / (DIMCELY / 2)) + 0; + + if (GetInfoHeight () != 0) + { + nbx += 2; + nby += 2; + } + + this->FixShifting (nbx, nby, iCel, iPos); + + // Construit les sols. + mCel = iCel; + mPos = iPos; + for (j = 0; j < nby; j++) + { + x = mCel.x; + y = mCel.y; + cPos = mPos; + for (i = 0; i < nbx; i++) + { + if (x >= 2 && x < MAXCELX - 2 && y >= 2 && y < MAXCELY - 2) + { + m_rankBlupi[x][y] = -1; // (1), voir BuildPutBlupi + + if (x % 2 == 0 && y % 2 == 0) + { + icon = m_decor[x / 2][y / 2].floorIcon; + + if (!m_bBuild && icon == 71) // terre à fer ? + { + icon = 33; // terre normale ! + } + + // Dessine l'eau sous les rives et les ponts. + if ( + (icon >= 2 && icon <= 14) || // rive ? + (icon >= 59 && icon <= 64)) // pont ? + { + // Dessine l'eau en mouvement. + pos.x = cPos.x - DIMCELX / 2; + pos.y = cPos.y; + n = table_eau + [(m_timeConst / 2 + // lent ! + table_random_x[x % 10] + table_random_y[y % 10]) % + 6]; + m_pPixmap->DrawIcon (CHGROUND, CHFLOOR, n, pos); // eau + if (icon != 14) + m_pPixmap->DrawIcon (CHGROUND, CHFLOOR, icon, pos); + } + + rank = m_decor[x / 2][y / 2].rankMove; + if ( + rank != -1 && // décor animé ? + m_move[rank].bFloor) + { + pos.x = cPos.x - DIMCELX / 2; + pos.y = cPos.y; + + BuildMoveFloor (x, y, pos, rank); + } + } + } + + if ( + m_celHili.x != -1 && x >= m_celHili.x - 1 && x <= m_celHili.x + 2 && + y >= m_celHili.y - 1 && y <= m_celHili.y + 2) + { + icon = m_iconHili[x - (m_celHili.x - 1)][y - (m_celHili.y - 1)]; + if (icon != -1) + { + // hilight cellule + m_pPixmap->DrawIconDemi (-1, CHBLUPI, icon, cPos); + } + } + + if (m_bHiliRect) // rectangle de sélection existe ? + { + if ( + (m_p1Hili.x == x && m_p1Hili.y == y) || + (m_p2Hili.x == x && m_p2Hili.y == y)) + m_pPixmap->DrawIconDemi (-1, CHBLUPI, ICON_HILI_SEL, cPos); + } + + x++; + y--; + cPos.x += DIMCELX; + } + + if (j % 2 == 0) + { + mCel.y++; + mPos.x -= DIMCELX / 2; + mPos.y += DIMCELY / 2; + } + else + { + mCel.x++; + mPos.x += DIMCELX / 2; + mPos.y += DIMCELY / 2; + } + } + + for (j = nby; j < nby + 3; j++) + { + x = mCel.x; + y = mCel.y; + for (i = 0; i < nbx; i++) + { + if (x >= 2 && x < MAXCELX - 2 && y >= 2 && y < MAXCELY - 2) + { + m_rankBlupi[x][y] = -1; // (1), voir BuildPutBlupi + } + x++; + y--; + } + + if (j % 2 == 0) + mCel.y++; + else + mCel.x++; + } + + BlupiDrawHili (); // dessine le rectangle de sélection + + // Construit les objets et les blupi. + BuildPutBlupi (); // m_rankBlupi[x][y] <- rangs des blupi + + this->FixShifting (nbx, nby, iCel, iPos); + + mCel = iCel; + mPos = iPos; + for (j = 0; j < nby + 3; j++) + { + x = mCel.x; + y = mCel.y; + cPos = mPos; + for (i = 0; i < nbx; i++) + { + if (x >= 2 && x < MAXCELX - 2 && y >= 2 && y < MAXCELY - 2) + { + rank = m_rankBlupi[x][y]; + if ( + rank != -1 && // un blupi sur cette cellule ? + !m_blupi[rank].bCache && m_blupi[rank].bExist) + { + cel.x = m_blupi[rank].cel.x; + cel.y = m_blupi[rank].cel.y; + pos = ConvCelToPos (cel); + pos.x += m_blupi[rank].pos.x; + pos.y += m_blupi[rank].pos.y - (DIMBLUPIY - DIMCELY) - SHIFTBLUPIY; + + if (m_blupi[rank].bHili) + { + icon = 120 + (m_blupi[rank].energy * 18) / MAXENERGY; + if (icon < 120) + icon = 120; + if (icon > 137) + icon = 137; + tPos = pos; + tPos.y += DIMCELY; + if (m_blupi[rank].vehicule == 1) // en bateau ? + tPos.y -= 6; + // Dessine la sélection/énergie + if (m_blupi[rank].clipLeft == 0) + m_pPixmap->DrawIconDemi (-1, CHBLUPI, icon, tPos); + else + { + clipRect = clip; + clipRect.left = m_blupi[rank].clipLeft; + m_pPixmap->SetClipping (clipRect); + m_pPixmap->DrawIconDemi (-1, CHBLUPI, icon, tPos); + m_pPixmap->SetClipping (clip); + } + } + + // Dessine la flèche ronde "répète" sous blupi. + if (m_blupi[rank].repeatLevel != -1) + { + tPos = pos; + tPos.y += DIMCELY; + if (m_blupi[rank].vehicule == 1) // en bateau ? + tPos.y -= 6; + // Dessine la sélection/énergie + if (m_blupi[rank].clipLeft == 0) + m_pPixmap->DrawIconDemi (-1, CHBLUPI, 116, tPos); + else + { + clipRect = clip; + clipRect.left = m_blupi[rank].clipLeft; + m_pPixmap->SetClipping (clipRect); + m_pPixmap->DrawIconDemi (-1, CHBLUPI, 116, tPos); + m_pPixmap->SetClipping (clip); + } + } + + // Dessine la flèche jaune sur blupi. + if (m_blupi[rank].bArrow) + { + tPos = pos; + if (m_phase % (6 * 2) < 6) + tPos.y -= DIMBLUPIY + (m_phase % 6) * 4; + else + tPos.y -= DIMBLUPIY + (6 - (m_phase % 6) - 1) * 4; + m_pPixmap->DrawIcon (-1, CHBLUPI, 132, tPos); + } + + // Dessine le stop sur blupi. + if (m_blupi[rank].stop == 1) + { + tPos = pos; + tPos.x += 9; + tPos.y -= 24; + m_pPixmap->DrawIcon ( + -1, CHBUTTON, IsRightReading () ? 115 : 46, tPos); + } + + // Dessine blupi + pos.y += m_blupi[rank].posZ; + + if (m_blupi[rank].clipLeft == 0) + { + m_pPixmap->DrawIcon ( + -1, m_blupi[rank].channel, m_blupi[rank].icon, pos); + + // Dessine l'objet transporté. + if (m_blupi[rank].takeChannel != -1) + { + BuildMoveTransport (m_blupi[rank].icon, pos); + m_pPixmap->DrawIcon ( + -1, m_blupi[rank].takeChannel, m_blupi[rank].takeIcon, pos); + } + } + else + { + clipRect = clip; + clipRect.left = m_blupi[rank].clipLeft; + m_pPixmap->SetClipping (clipRect); + m_pPixmap->DrawIcon ( + -1, m_blupi[rank].channel, m_blupi[rank].icon, pos); + + // Dessine l'objet transporté. + if (m_blupi[rank].takeChannel != -1) + { + BuildMoveTransport (m_blupi[rank].icon, pos); + m_pPixmap->DrawIcon ( + -1, m_blupi[rank].takeChannel, m_blupi[rank].takeIcon, pos); + } + m_pPixmap->SetClipping (clip); + } + } + + if (x % 2 == 0 && y % 2 == 0) + { + rank = m_decor[x / 2][y / 2].rankMove; + if (m_decor[x / 2][y / 2].objectChannel >= 0) + { + pos.x = cPos.x - DIMCELX / 2; + pos.y = cPos.y - (DIMOBJY - DIMCELY * 2); + + // Dessine l'objet + if ( + rank == -1 || // décor fixe ? + m_move[rank].bFloor || m_bBuild) + { + channel = m_decor[x / 2][y / 2].objectChannel; + if (m_bOutline && channel == CHOBJECT) + channel = CHOBJECTo; + if ( + m_celOutline1.x != -1 && x >= m_celOutline1.x && + y >= m_celOutline1.y && x <= m_celOutline2.x && + y <= m_celOutline2.y) + { + if (channel == CHOBJECT) + channel = CHOBJECTo; + else + channel = CHOBJECT; + } + m_pPixmap->DrawIcon ( + -1, channel, m_decor[x / 2][y / 2].objectIcon, pos); + + if (m_decor[x / 2][y / 2].objectIcon == 12) // fusée ? + { + pos.y -= DIMOBJY; + m_pPixmap->DrawIcon (-1, channel, 13, pos); + } + } + else // décor animé ? + BuildMoveObject (x, y, pos, rank); + } + else + { + if ( + rank != -1 && // décor animé ? + !m_move[rank].bFloor && !m_bBuild) + { + pos.x = cPos.x - DIMCELX / 2; + pos.y = cPos.y - (DIMOBJY - DIMCELY * 2); + BuildMoveObject (x, y, pos, rank); + } + } + + // Dessine le feu en mode construction. + if ( + m_bBuild && m_decor[x / 2][y / 2].fire > 0 && + m_decor[x / 2][y / 2].fire < MoveMaxFire ()) + { + pos.x = cPos.x - DIMCELX / 2; + pos.y = cPos.y - (DIMOBJY - DIMCELY * 2); + m_pPixmap->DrawIcon (-1, CHOBJECT, 49, pos); // petite flamme + } + } + } + + x++; + y--; + cPos.x += DIMCELX; + } + + if (j % 2 == 0) + { + mCel.y++; + mPos.x -= DIMCELX / 2; + mPos.y += DIMCELY / 2; + } + else + { + mCel.x++; + mPos.x += DIMCELX / 2; + mPos.y += DIMCELY / 2; + } + } + + // Construit le brouillard. + if (!m_bFog) + goto term; + + this->FixShifting (nbx, nby, iCel, iPos); + + mCel = iCel; + mPos = iPos; + for (j = 0; j < nby; j++) + { + x = mCel.x; + y = mCel.y; + cPos = mPos; + for (i = 0; i < nbx; i++) + { + if ( + x >= 0 && x < MAXCELX && y >= 0 && y < MAXCELY && x % 2 == 0 && + y % 2 == 0) + icon = m_decor[x / 2][y / 2].fog; + else + { + icon = FOGHIDE; // caché + } + + if ( + abs (x) % 4 == abs (y) % 4 && (abs (x) % 4 == 0 || abs (x) % 4 == 2) && + icon != -1) + { + pos.x = cPos.x - DIMCELX / 2; + pos.y = cPos.y; + + m_pPixmap->DrawIcon (-1, CHFOG, icon, pos); + } + + x++; + y--; + cPos.x += DIMCELX; + } + + if (j % 2 == 0) + { + mCel.y++; + mPos.x -= DIMCELX / 2; + mPos.y += DIMCELY / 2; + } + else + { + mCel.x++; + mPos.x += DIMCELX / 2; + mPos.y += DIMCELY / 2; + } + } + +term: + // Dessine la flèche jaune sur un objet. + if (m_celArrow.x != -1) + { + tPos = ConvCelToPos (m_celArrow); + if (m_phase % (6 * 2) < 6) + tPos.y -= DIMBLUPIY + (m_phase % 6) * 4; + else + tPos.y -= DIMBLUPIY + (6 - (m_phase % 6) - 1) * 4; + m_pPixmap->DrawIcon (-1, CHBLUPI, 132, tPos); + } + + // Dessine le nom de l'objet pointé par la souris. + if (posMouse.x == m_textLastPos.x && posMouse.y == m_textLastPos.y) + { + if (m_textCount == 0) + { + const auto text = GetResHili (posMouse); + if (text) + { + posMouse.x += IsRightReading () ? 0 : 10; + posMouse.y += 20; + DrawText (m_pPixmap, posMouse, text); + } + } + else + m_textCount--; + } + else + { + m_textLastPos = posMouse; + m_textCount = TEXTDELAY; + } + + m_pPixmap->SetClipping (oldClip); + + GenerateMap (); // dessine la carte miniature + GenerateStatictic (); // dessine les statistiques +} + +// Augmente la phase. +// -1 mise à jour continue +// 0 début de mise à jour périodique +// 1 mise à jour périodique suivante + +void +CDecor::NextPhase (Sint32 mode) +{ + if (mode == -1) + m_phase = -1; + + if (mode == 0) + m_phase = 0; + + if (mode == 1) + m_phase++; + + m_totalTime++; +} + +// Modifie le temps total passé dans cette partie. + +void +CDecor::SetTotalTime (Sint32 total) +{ + m_totalTime = total; +} + +// Retourne le temps total passé dans cette partie. + +Sint32 +CDecor::GetTotalTime () +{ + return m_totalTime; +} + +// Compte le nombre total de sols contenus dans les décors. + +Sint32 +CDecor::CountFloor (Sint32 channel, Sint32 icon) +{ + Sint32 x, y; + Sint32 nb = 0; + + for (x = 0; x < MAXCELX / 2; x++) + { + for (y = 0; y < MAXCELY / 2; y++) + { + if ( + channel == m_decor[x][y].floorChannel && + icon == m_decor[x][y].floorIcon) + nb++; + } + } + + return nb; +} + +// Indique si une cellule est ok pour une action. +// Le rang du blupi qui effectuera le travail est donnée dans rank. +// action = 0 sélection jeu +// 1 construction d'une cellule 1x1 +// 2 construction d'une cellule 2x2 +// EV_ACTION* action + +Errors +CDecor::CelOkForAction ( + Point cel, Sint32 action, Sint32 rank, Sint32 icons[4][4], + Point & celOutline1, Point & celOutline2) +{ + Sint32 x, y, i, j, channel, icon, nb, start, direct; + Errors error = Errors::NONE; + bool bStrong = false; + bool bTransport = false; + bool bVehicule = false; + bool bVehiculeA = false; + Point vector; + + for (x = 0; x < 4; x++) + { + for (y = 0; y < 4; y++) + icons[x][y] = -1; + } + + celOutline1.x = -1; + celOutline2.x = -1; + + if ( + action == 2 || action == EV_ACTION_ABAT1 || action == EV_ACTION_ROC1 || + action == EV_ACTION_DROP || action == EV_ACTION_LABO || + action == EV_ACTION_FABJEEP || action == EV_ACTION_FABARMURE || + action == EV_ACTION_FABMINE || action == EV_ACTION_FLOWER1 || + action == EV_ACTION_CULTIVE || action == EV_ACTION_FLAG) + { + cel.x = (cel.x / 2) * 2; + cel.y = (cel.y / 2) * 2; + } + + if (rank >= 0) + { + if (m_blupi[rank].energy > MAXENERGY / 4) // blupi fort ? + bStrong = true; + if (m_blupi[rank].takeChannel != -1) // porte qq chose ? + bTransport = true; + if (m_blupi[rank].vehicule != 0) // pas à pied ? + bVehicule = true; + if ( + m_blupi[rank].vehicule != 0 && // pas à pied ? + m_blupi[rank].vehicule != 3) // pas armure ? + bVehiculeA = true; + } + + if (action == 0) + { + if (IsBlupiHere (cel, false)) + icons[1][1] = ICON_HILI_SEL; + else + { + if (IsFreeCel (cel, -1) && m_nbBlupiHili > 0) + icons[1][1] = ICON_HILI_ANY; + else + icons[1][1] = ICON_HILI_ERR; + } + } + + if (action == 1) + { + icons[1][1] = ICON_HILI_BUILD; // action + } + + if (action == 2) + { + icons[1][1] = ICON_HILI_BUILD; // action + icons[2][1] = ICON_HILI_BUILD; + icons[1][2] = ICON_HILI_BUILD; + icons[2][2] = ICON_HILI_BUILD; + } + + if (action == EV_ACTION_STOP) + { + error = Errors::MISC; + if ( + m_blupi[rank].stop == 0 && + (m_blupi[rank].goalAction == EV_ACTION_GO || + (m_blupi[rank].goalAction >= EV_ACTION_ABAT1 && + m_blupi[rank].goalAction <= EV_ACTION_ABAT6) || + (m_blupi[rank].goalAction >= EV_ACTION_ROC1 && + m_blupi[rank].goalAction <= EV_ACTION_ROC7) || + m_blupi[rank].goalAction == EV_ACTION_CULTIVE || + m_blupi[rank].goalAction == EV_ACTION_CULTIVE2 || + m_blupi[rank].goalAction == EV_ACTION_FLAG || + m_blupi[rank].goalAction == EV_ACTION_FLAG2 || + m_blupi[rank].goalAction == EV_ACTION_FLAG3 || + m_blupi[rank].goalAction == EV_ACTION_FLOWER1 || + m_blupi[rank].goalAction == EV_ACTION_FLOWER2 || + m_blupi[rank].goalAction == EV_ACTION_FLOWER3)) + error = Errors::NONE; + if ( + m_blupi[rank].stop == 0 && m_blupi[rank].goalAction != 0 && + m_blupi[rank].interrupt == 1) + error = Errors::NONE; + if (m_blupi[rank].repeatLevel != -1) + error = Errors::NONE; + } + + if (action == EV_ACTION_GO) + { + if (m_decor[cel.x / 2][cel.y / 2].objectIcon == 113) // maison ? + { + cel.x = (cel.x / 2) * 2 + 1; + cel.y = (cel.y / 2) * 2 + 1; + } + error = Errors::MISC; + if (m_nbBlupiHili > 0) + { + nb = m_nbBlupiHili; + if (nb > 16) + nb = 16; + for (i = 0; i < nb; i++) + { + x = table_multi_goal[i * 2 + 0]; + y = table_multi_goal[i * 2 + 1]; + rank = GetHiliRankBlupi (i); + if ( + ((m_blupi[rank].takeChannel == -1) || + (m_blupi[rank].energy > MAXENERGY / 4)) && + IsFreeCelGo (GetCel (cel.x + x, cel.y + y), rank) && + !IsBlupiHere (GetCel (cel.x + x, cel.y + y), true)) + { + icons[1 + x][1 + y] = ICON_HILI_OP; // action + error = Errors::NONE; + } + else + icons[1 + x][1 + y] = ICON_HILI_ERR; + } + } + else + icons[1][1] = ICON_HILI_ERR; + } + + if (action == EV_ACTION_ABAT1) + { + GetObject (cel, channel, icon); + if ( + bStrong && !bTransport && !bVehicule && channel == CHOBJECT && + icon >= 6 && icon <= 11 && // arbre ? + !MoveIsUsed (cel) && IsWorkableObject (cel, rank)) + { + icons[1][1] = ICON_HILI_OP; // action + icons[2][1] = ICON_HILI_OP; + icons[1][2] = ICON_HILI_OP; + icons[2][2] = ICON_HILI_OP; + celOutline1 = cel; + celOutline2 = cel; + } + else + { + icons[1][1] = ICON_HILI_ERR; // croix + icons[2][1] = ICON_HILI_ERR; + icons[1][2] = ICON_HILI_ERR; + icons[2][2] = ICON_HILI_ERR; + error = Errors::MISC; + } + } + + if (action == EV_ACTION_ROC1) + { + GetObject (cel, channel, icon); + if ( + bStrong && !bTransport && !bVehicule && + m_blupi[rank].perso != 8 && // pas disciple ? + channel == CHOBJECT && icon >= 37 && icon <= 43 && // rochers ? + !MoveIsUsed (cel) && IsWorkableObject (cel, rank)) + { + icons[1][1] = ICON_HILI_OP; // action + icons[2][1] = ICON_HILI_OP; + icons[1][2] = ICON_HILI_OP; + icons[2][2] = ICON_HILI_OP; + celOutline1 = cel; + celOutline2 = cel; + } + else + { + icons[1][1] = ICON_HILI_ERR; // croix + icons[2][1] = ICON_HILI_ERR; + icons[1][2] = ICON_HILI_ERR; + icons[2][2] = ICON_HILI_ERR; + error = Errors::MISC; + } + } + + if (action >= EV_ACTION_BUILD1 && action <= EV_ACTION_BUILD6) + { + if (cel.x % 2 != 1 || cel.y % 2 != 1) + { + icons[1][1] = ICON_HILI_ERR; + error = Errors::MISC; + } + else + { + cel.x--; + cel.y--; + + if (!bStrong || bTransport || bVehicule) + { + error = Errors::MISC; // pas assez fort + } + + if ( + action == EV_ACTION_BUILD1 || // cabane ? + action == EV_ACTION_BUILD2 || // couveuse ? + action == EV_ACTION_BUILD6) // téléporteur ? + { + GetFloor (cel, channel, icon); + if ( + channel != CHFLOOR || (icon != 1 && // herbe claire ? + (icon < 19 || icon > 32))) // herbe foncée ? + { + error = Errors::GROUND; // sol pas adéquat + } + } + + GetFloor (cel, channel, icon); + if ( // mine ? + action == EV_ACTION_BUILD4 && + ((!g_restoreBugs && + !m_decorMem[cel.x / 2][cel.y / 2].flagged) || // fixed + (g_restoreBugs && (channel != CHFLOOR || icon != 71)))) // funny bug + { + error = Errors::GROUND; // sol pas adéquat + } + + if ( + action == EV_ACTION_BUILD6 && // téléporteur ? + CountFloor (CHFLOOR, 80) >= 2) // déjà 2 ? + { + error = Errors::TELE2; // déjà 2 téléporteurs + } + + if (action == EV_ACTION_BUILD3 || action == EV_ACTION_BUILD5) + start = 44; // pierres + else + start = 36; // planches + if (start == 44 && m_blupi[rank].perso == 8) + start = 999; // disciple ? + + GetObject (cel, channel, icon); + if (channel != CHOBJECT || icon != start) // planches ? + { + error = Errors::MISC; // pas de planches ! + } + + for (x = -1; x < 3; x++) + { + for (y = -1; y < 3; y++) + { + if (error) + icons[x + 1][y + 1] = ICON_HILI_ERR; + else + icons[x + 1][y + 1] = ICON_HILI_OP; + } + } + + for (x = -1; x < 3; x++) + { + for (y = -1; y < 3; y++) + { + if ( + (x < 0 || x > 1 || y < 0 || y > 1) && + !IsFreeCel (GetCel (cel, x, y), rank)) + { + error = Errors::FREE; + icons[x + 1][y + 1] = ICON_HILI_ERR; // croix + } + if (IsBlupiHereEx (GetCel (cel, x, y), rank, false)) + { + error = Errors::FREE; + icons[x + 1][y + 1] = ICON_HILI_ERR; // croix + } + } + } + } + } + + if (action == EV_ACTION_WALL) + { + if (cel.x % 2 != 1 || cel.y % 2 != 1) + { + icons[1][1] = ICON_HILI_ERR; + error = Errors::MISC; + } + else + { + cel.x--; + cel.y--; + + if ( + !bStrong || bTransport || bVehicule || + m_blupi[rank].perso == 8) // disciple ? + { + error = Errors::MISC; // pas assez fort + } + + if (m_blupi[rank].energy <= MAXENERGY / 2) + error = Errors::ENERGY; // not enough energy + + GetObject (cel, channel, icon); + if (channel != CHOBJECT || icon != 44) // pierres ? + { + error = Errors::MISC; // pas de pierres ! + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (error) + icons[x + 1][y + 1] = ICON_HILI_ERR; + else + icons[x + 1][y + 1] = ICON_HILI_OP; + } + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (IsBlupiHereEx (GetCel (cel, x, y), rank, false)) + { + error = Errors::FREE; + icons[x + 1][y + 1] = ICON_HILI_ERR; // croix + } + } + } + } + } + + if (action == EV_ACTION_TOWER) + { + bool bTour; + + if (cel.x % 2 != 1 || cel.y % 2 != 1) + { + icons[1][1] = ICON_HILI_ERR; + error = Errors::MISC; + } + else + { + cel.x--; + cel.y--; + + if ( + !bStrong || bTransport || bVehicule || + m_blupi[rank].perso == 8) // disciple ? + { + error = Errors::MISC; // pas assez fort + } + + if (m_blupi[rank].energy <= MAXENERGY / 2) + error = Errors::ENERGY; // not enough energy + + GetObject (cel, channel, icon); + if (channel != CHOBJECT || icon != 44) // pierres ? + { + error = Errors::MISC; // pas de pierres ! + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (error) + icons[x + 1][y + 1] = ICON_HILI_ERR; + else + icons[x + 1][y + 1] = ICON_HILI_OP; + } + } + + for (x = -1; x < 3; x++) + { + for (y = -1; y < 3; y++) + { + if (x < 0 || x > 1 || y < 0 || y > 1) // périphérie ? + { + GetFloor (GetCel (cel, x, y), channel, icon); + if (channel == CHFLOOR && (icon >= 2 && icon <= 13)) // rive ? + { + error = Errors::TOUREAU; + icons[x + 1][y + 1] = ICON_HILI_ERR; // croix + } + } + if (IsBlupiHereEx (GetCel (cel, x, y), rank, false)) + { + error = Errors::FREE; + icons[x + 1][y + 1] = ICON_HILI_ERR; // croix + } + } + } + + if (error == 0) + { + bTour = false; + for (i = 0; i < 4; i++) + { + vector = GetVector (i * 2 * 16); + x = cel.x; + y = cel.y; + + for (j = 0; j < 3; j++) + { + x += vector.x * 2; + y += vector.y * 2; + + if (m_decor[x / 2][y / 2].objectIcon == 27) // tour ? + bTour = true; + + if ( + MoveGetObject (GetCel (x, y), channel, icon) && + channel == CHOBJECT && icon == 27) // tour en construction ? + bTour = true; + } + } + if (!bTour) + error = Errors::TOURISOL; + } + } + } + + if (action == EV_ACTION_PALIS) + { + if (cel.x % 2 != 1 || cel.y % 2 != 1) + { + icons[1][1] = ICON_HILI_ERR; + error = Errors::MISC; + } + else + { + cel.x--; + cel.y--; + + if (!bStrong || bTransport || bVehicule) + { + error = Errors::MISC; // pas assez fort + } + + GetObject (cel, channel, icon); + if (channel != CHOBJECT || icon != 36) // planches ? + { + error = Errors::MISC; // pas de pierres ! + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (error) + icons[x + 1][y + 1] = ICON_HILI_ERR; + else + icons[x + 1][y + 1] = ICON_HILI_OP; + } + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (IsBlupiHereEx (GetCel (cel, x, y), rank, false)) + { + error = Errors::FREE; + icons[x + 1][y + 1] = ICON_HILI_ERR; // croix + } + } + } + } + } + + if (action == EV_ACTION_BRIDGEE) + { + Point test; + + if (cel.x % 2 != 1 || cel.y % 2 != 1) + { + icons[1][1] = ICON_HILI_ERR; + error = Errors::MISC; + } + else + { + cel.x--; + cel.y--; + + if (!bStrong || bTransport || bVehicule) + { + error = Errors::MISC; // pas assez fort + } + + GetObject (cel, channel, icon); + if (channel != CHOBJECT || icon != 36) // planches ? + { + error = Errors::MISC; // pas de pierres ! + } + + test = cel; + if (error == 0) + error = IsBuildPont (test, icon); + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (error) + icons[x + 1][y + 1] = ICON_HILI_ERR; + else + icons[x + 1][y + 1] = ICON_HILI_OP; + } + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (IsBlupiHereEx (GetCel (cel, x, y), rank, false)) + { + error = Errors::FREE; + icons[x + 1][y + 1] = ICON_HILI_ERR; // croix + } + } + } + } + } + + if (action == EV_ACTION_CARRY) + { + if (cel.x % 2 != 1 || cel.y % 2 != 1) + { + icons[1][1] = ICON_HILI_ERR; + error = Errors::MISC; + } + else + { + GetObject (GetCel (cel, -1, -1), channel, icon); + if ( + bStrong && !bTransport && !bVehiculeA && channel == CHOBJECT && + (icon == 14 || // métal ? + icon == 36 || // planches ? + icon == 44 || // pierres ? + icon == 60 || // tomates ? + icon == 63 || // oeufs ? + icon == 80 || // bouteille ? + icon == 82 || // fleurs ? + icon == 84 || // fleurs ? + icon == 95 || // fleurs ? + icon == 85 || // dynamite ? + icon == 92 || // poison ? + icon == 93 || // piège ? + icon == 123 || // fer ? + icon == 125) && // mine ? + (!IsBlupiHereEx (GetCel (cel, -1, 0), rank, false) || + !IsBlupiHereEx (GetCel (cel, 0, -1), rank, false))) + { + icons[1][1] = ICON_HILI_OP; // action + } + else + { + icons[1][1] = ICON_HILI_ERR; // croix + error = Errors::MISC; + } + } + } + + if (action == EV_ACTION_DROP) + { + if (!bTransport || bVehiculeA) + { + error = Errors::MISC; // ne transporte rien + } + + GetObject (GetCel ((cel.x / 2) * 2, (cel.y / 2) * 2), channel, icon); + if (icon != -1 && icon != 124) // pas drapeau ? + error = Errors::MISC; + + start = 0; + if (error == 0) + { + GetFloor (cel, channel, icon); + if ( + channel == CHFLOOR && icon == 52 && // nurserie ? + m_blupi[rank].takeChannel == CHOBJECT && + m_blupi[rank].takeIcon == 63) // oeufs ? + { + for (x = -1; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if ( + !IsFreeCelDepose (GetCel (cel, x, y), rank) || + IsBlupiHereEx (GetCel (cel, x, y), rank, false)) + error = Errors::MISC; + } + } + start = -1; + } + else + { + if ( + !IsFreeCelDepose (GetCel (cel, 1, 1), rank) || + IsBlupiHereEx (GetCel (cel, 1, 1), rank, false)) + error = Errors::MISC; + else + { + if ( + !IsFreeCelDepose (GetCel (cel, 0, 1), rank) || + IsBlupiHereEx (GetCel (cel, 0, 1), rank, false)) + { + if ( + !IsFreeCelDepose (GetCel (cel, 1, 0), rank) || + IsBlupiHereEx (GetCel (cel, 1, 0), rank, false)) + error = Errors::MISC; + } + } + } + } + + for (x = start; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (error) + icons[x + 1][y + 1] = ICON_HILI_ERR; + else + icons[x + 1][y + 1] = ICON_HILI_OP; + } + } + } + + if (action == EV_ACTION_CULTIVE) + { + if (!bStrong || bTransport || bVehicule) + { + error = Errors::MISC; // pas assez fort + } + + GetObject (cel, channel, icon); + if (channel != CHOBJECT || icon != 61) // maison ? + { + error = Errors::MISC; // pas de maison ! + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (error) + icons[x + 1][y + 1] = ICON_HILI_ERR; + else + icons[x + 1][y + 1] = ICON_HILI_OP; + } + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (IsBlupiHereEx (GetCel (cel, x, y), rank, false)) + { + error = Errors::MISC; + icons[x + 1][y + 1] = ICON_HILI_ERR; // croix + } + } + } + } + + if (action == EV_ACTION_LABO) + { + if (!bStrong || !bTransport || bVehicule) + { + error = Errors::MISC; // pas assez fort + } + + GetObject (cel, channel, icon); + if ( + channel != CHOBJECT || icon != 28 || // laboratoire ? + m_blupi[rank].takeChannel != CHOBJECT || + (m_blupi[rank].takeIcon != 82 && // fleurs ? + m_blupi[rank].takeIcon != 84 && // fleurs ? + m_blupi[rank].takeIcon != 95 && // fleurs ? + m_blupi[rank].takeIcon != 60)) // tomates ? + { + error = Errors::MISC; // pas de laboratoire ! + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (error) + icons[x + 1][y + 1] = ICON_HILI_ERR; + else + icons[x + 1][y + 1] = ICON_HILI_OP; + } + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (IsBlupiHereEx (GetCel (cel, x, y), rank, false)) + { + error = Errors::MISC; + icons[x + 1][y + 1] = ICON_HILI_ERR; // croix + } + } + } + } + + if (action == EV_ACTION_FLOWER1) + { + GetObject (cel, channel, icon); + if ( + bStrong && !bTransport && !bVehicule && channel == CHOBJECT && + (icon == 81 || icon == 83 || icon == 94) && // fleurs ? + !MoveIsUsed (cel) && IsWorkableObject (cel, rank)) + { + icons[1][1] = ICON_HILI_OP; // action + icons[2][1] = ICON_HILI_OP; + icons[1][2] = ICON_HILI_OP; + icons[2][2] = ICON_HILI_OP; + celOutline1 = cel; + celOutline2 = cel; + } + else + { + icons[1][1] = ICON_HILI_ERR; // croix + icons[2][1] = ICON_HILI_ERR; + icons[1][2] = ICON_HILI_ERR; + icons[2][2] = ICON_HILI_ERR; + error = Errors::MISC; + } + } + + if (action == EV_ACTION_DYNAMITE) + { + if (cel.x % 2 != 1 || cel.y % 2 != 1) + { + icons[1][1] = ICON_HILI_ERR; + error = Errors::MISC; + } + else + { + cel.x--; + cel.y--; + + //? if ( !bStrong || bVehicule ) + if (bVehiculeA) + { + error = Errors::MISC; // pas assez fort + } + + GetObject (cel, channel, icon); + if (icon != 85 && icon != 125) // dynamite/mine ? + { + error = Errors::MISC; // pas de dynamite ! + } + + for (x = 0; x < 2; x++) + { + for (y = 1; y < 2; y++) + { + if (error) + icons[x + 1][y + 1] = ICON_HILI_ERR; + else + icons[x + 1][y + 1] = ICON_HILI_OP; + } + } + + for (x = 0; x < 2; x++) + { + for (y = 1; y < 2; y++) + { + if ( + (x < 0 || x > 1 || y < 0 || y > 1) && + !IsFreeCel (GetCel (cel, x, y), rank)) + { + error = Errors::FREE; + icons[x + 1][y + 1] = ICON_HILI_ERR; // croix + } + if (IsBlupiHereEx (GetCel (cel, x, y), rank, false)) + { + error = Errors::FREE; + icons[x + 1][y + 1] = ICON_HILI_ERR; // croix + } + } + } + } + } + + if (action == EV_ACTION_EAT) + { + if (cel.x % 2 != 1 || cel.y % 2 != 1) + { + icons[1][1] = ICON_HILI_ERR; + error = Errors::MISC; + } + else + { + GetObject (GetCel (cel, -1, -1), channel, icon); + if ( + !m_blupi[rank].bMalade && !bVehicule && + m_blupi[rank].perso != 8 && // pas disciple ? + channel == CHOBJECT && icon == 60 && // tomates ? + (!IsBlupiHereEx (GetCel (cel, -1, 0), rank, false) || + !IsBlupiHereEx (GetCel (cel, 0, -1), rank, false))) + { + icons[1][1] = ICON_HILI_OP; // action + } + else + { + icons[1][1] = ICON_HILI_ERR; // croix + error = Errors::MISC; + } + } + } + + if (action == EV_ACTION_DRINK) + { + if (cel.x % 2 != 1 || cel.y % 2 != 1) + { + icons[1][1] = ICON_HILI_ERR; + error = Errors::MISC; + } + else + { + GetObject (GetCel (cel, -1, -1), channel, icon); + if ( + m_blupi[rank].bMalade && !bVehicule && + m_blupi[rank].perso != 8 && // pas disciple ? + channel == CHOBJECT && icon == 80 && // bouteille ? + (!IsBlupiHereEx (GetCel (cel, -1, 0), rank, false) || + !IsBlupiHereEx (GetCel (cel, 0, -1), rank, false))) + { + icons[1][1] = ICON_HILI_OP; // action + } + else + { + icons[1][1] = ICON_HILI_ERR; // croix + error = Errors::MISC; + } + } + } + + if (action == EV_ACTION_BOATE) + { + Point test; + + if (cel.x % 2 != 1 || cel.y % 2 != 1) + { + icons[1][1] = ICON_HILI_ERR; + error = Errors::MISC; + } + else + { + cel.x--; + cel.y--; + + if (!bStrong || bTransport || bVehicule) + { + error = Errors::MISC; // pas assez fort + } + + GetObject (cel, channel, icon); + if (channel != CHOBJECT || icon != 36) // planches ? + { + error = Errors::MISC; // pas de pierres ! + } + + test = cel; + if (error == 0 && !IsBuildBateau (test, direct)) + { + error = Errors::MISC; // impossible ici ! + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (error) + icons[x + 1][y + 1] = ICON_HILI_ERR; + else + icons[x + 1][y + 1] = ICON_HILI_OP; + } + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (IsBlupiHereEx (GetCel (cel, x, y), rank, false)) + { + error = Errors::FREE; + icons[x + 1][y + 1] = ICON_HILI_ERR; // croix + } + } + } + } + } + + if (action == EV_ACTION_DJEEP) + { + cel.x = (cel.x / 2) * 2; + cel.y = (cel.y / 2) * 2; + error = Errors::MISC; + if ( + m_blupi[rank].vehicule == 2 && // en jeep ? + m_decor[cel.x / 2][cel.y / 2].objectIcon == -1 && + m_decor[cel.x / 2][cel.y / 2].floorIcon != 80) // pas téléporteur ? + { + if ( + IsFreeCelGo (GetCel (cel, +1, 0), rank) && + IsFreeCelGo (GetCel (cel, +1, +1), rank) && + !IsBlupiHereEx (GetCel (cel, +1, 0), rank, false) && + !IsBlupiHereEx (GetCel (cel, +1, +1), rank, false)) + { + icons[1][1] = ICON_HILI_OP; // action + icons[2][1] = ICON_HILI_OP; + icons[1][2] = ICON_HILI_OP; + icons[2][2] = ICON_HILI_OP; + error = Errors::NONE; + } + } + else + { + icons[1][1] = ICON_HILI_ERR; // croix + icons[2][1] = ICON_HILI_ERR; + icons[1][2] = ICON_HILI_ERR; + icons[2][2] = ICON_HILI_ERR; + } + } + + if (action == EV_ACTION_DARMURE) + { + cel.x = (cel.x / 2) * 2; + cel.y = (cel.y / 2) * 2; + error = Errors::MISC; + if ( + m_blupi[rank].vehicule == 3 && // armure ? + !bTransport && m_decor[cel.x / 2][cel.y / 2].objectIcon == -1 && + m_decor[cel.x / 2][cel.y / 2].floorIcon != 80) // pas téléporteur ? + { + if ( + IsFreeCelGo (GetCel (cel, +1, 0), rank) && + IsFreeCelGo (GetCel (cel, +1, +1), rank) && + !IsBlupiHereEx (GetCel (cel, +1, 0), rank, false) && + !IsBlupiHereEx (GetCel (cel, +1, +1), rank, false)) + { + icons[1][1] = ICON_HILI_OP; // action + icons[2][1] = ICON_HILI_OP; + icons[1][2] = ICON_HILI_OP; + icons[2][2] = ICON_HILI_OP; + error = Errors::NONE; + } + } + else + { + icons[1][1] = ICON_HILI_ERR; // croix + icons[2][1] = ICON_HILI_ERR; + icons[1][2] = ICON_HILI_ERR; + icons[2][2] = ICON_HILI_ERR; + } + } + + if (action == EV_ACTION_FLAG) + { + if (!bStrong || bTransport || bVehicule) + { + error = Errors::MISC; // pas assez fort + } + + GetFloor (cel, channel, icon); + if ((icon < 33 || icon > 48) && icon != 71) // pas terre ? + { + error = Errors::MISC; // terrain pas adapté + } + + GetObject (cel, channel, icon); + if (channel == CHOBJECT) // y a-t-il un objet ? + { + error = Errors::MISC; // terrain pas adapté + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (error) + icons[x + 1][y + 1] = ICON_HILI_ERR; + else + icons[x + 1][y + 1] = ICON_HILI_OP; + } + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (IsBlupiHereEx (GetCel (cel, x, y), rank, false)) + { + error = Errors::MISC; + icons[x + 1][y + 1] = ICON_HILI_ERR; // croix + } + } + } + } + + if (action == EV_ACTION_EXTRAIT) + { + if (!bStrong || bTransport || bVehicule) + { + error = Errors::MISC; // pas assez fort + } + + GetObject (cel, channel, icon); + if (channel != CHOBJECT || icon != 122) // mine de fer ? + { + error = Errors::MISC; // pas de mine + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (error) + icons[x + 1][y + 1] = ICON_HILI_ERR; + else + icons[x + 1][y + 1] = ICON_HILI_OP; + } + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (IsBlupiHereEx (GetCel (cel, x, y), rank, false)) + { + error = Errors::MISC; + icons[x + 1][y + 1] = ICON_HILI_ERR; // croix + } + } + } + } + + if ( + action == EV_ACTION_FABJEEP || action == EV_ACTION_FABMINE || + action == EV_ACTION_FABARMURE) + { + if (!bStrong || !bTransport || bVehicule) + { + error = Errors::MISC; // pas assez fort + } + if (action == EV_ACTION_FABJEEP && m_blupi[rank].perso == 8) // disciple ? + { + error = Errors::MISC; // impossible + } + if (action == EV_ACTION_FABARMURE && m_blupi[rank].perso == 8) // disciple ? + { + error = Errors::MISC; // impossible + } + + GetObject (cel, channel, icon); + if ( + channel != CHOBJECT || icon != 120 || // usine ? + m_blupi[rank].takeChannel != CHOBJECT || + m_blupi[rank].takeIcon != 123) // fer ? + { + error = Errors::MISC; // pas d'usine ! + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (error) + icons[x + 1][y + 1] = ICON_HILI_ERR; + else + icons[x + 1][y + 1] = ICON_HILI_OP; + } + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (IsBlupiHereEx (GetCel (cel, x, y), rank, false)) + { + error = Errors::MISC; + icons[x + 1][y + 1] = ICON_HILI_ERR; // croix + } + } + } + } + + if (action == EV_ACTION_FABDISC) + { + if (!bStrong || !bTransport || bVehicule) + { + error = Errors::MISC; // pas assez fort + } + + GetObject (cel, channel, icon); + if ( + channel != CHOBJECT || icon != 120 || // usine ? + m_blupi[rank].takeChannel != CHOBJECT || + m_blupi[rank].takeIcon != 14) // métal ? + { + error = Errors::MISC; // pas d'usine ! + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (error) + icons[x + 1][y + 1] = ICON_HILI_ERR; + else + icons[x + 1][y + 1] = ICON_HILI_OP; + } + } + + for (x = 0; x < 2; x++) + { + for (y = 0; y < 2; y++) + { + if (IsBlupiHereEx (GetCel (cel, x, y), rank, false)) + { + error = Errors::MISC; + icons[x + 1][y + 1] = ICON_HILI_ERR; // croix + } + } + } + } + + return error; +} + +// Indique si une cellule est ok pour une action. +// Le rang du blupi qui effectuera le travail est donnée dans rank. + +Errors +CDecor::CelOkForAction (Point cel, Sint32 action, Sint32 rank) +{ + Sint32 icons[4][4]; + Point celOutline1, celOutline2; + + return CelOkForAction (cel, action, rank, icons, celOutline1, celOutline2); +} + +// Retourne le rang du nième blupi sélectionné. + +Sint32 +CDecor::GetHiliRankBlupi (Sint32 nb) +{ + Sint32 rank; + + if (m_nbBlupiHili == 0) + return -1; + if (m_nbBlupiHili == 1) + { + if (nb == 0) + return m_rankBlupiHili; + return -1; + } + + for (rank = 0; rank < MAXBLUPI; rank++) + { + if (m_blupi[rank].bExist && m_blupi[rank].bHili) + { + if (nb == 0) + return rank; + nb--; + } + } + + return -1; +} + +// Marque la cellule visée par la souris. +// action = 0 sélection jeu +// 1 construction d'une cellule 1x1 +// 2 construction d'une cellule 2x2 + +void +CDecor::CelHili (Point pos, Sint32 action) +{ + Sint32 x, y, i, channel, icon, rank, nb; + Point cel; + + for (x = 0; x < 4; x++) + { + for (y = 0; y < 4; y++) + m_iconHili[x][y] = -1; + } + + m_celOutline1.x = -1; + m_celOutline2.x = -1; + m_rankHili = -1; + + if (action == 0) // sélection pendant jeu ? + { + rank = GetTargetBlupi (pos); + if (rank >= 0) + { + m_celHili = m_blupi[rank].cel; + m_rankHili = rank; + m_iconHili[1][1] = ICON_HILI_SEL; + } + else + { + m_celHili = ConvPosToCel (pos); + + if (IsBlupiHere (m_celHili, false)) + { + m_rankHili = m_blupiHere; + m_iconHili[1][1] = ICON_HILI_SEL; + } + else + { + if (m_nbBlupiHili > 0) + { + nb = m_nbBlupiHili; + if (nb > 16) + nb = 16; + for (i = 0; i < nb; i++) + { + x = table_multi_goal[i * 2 + 0]; + y = table_multi_goal[i * 2 + 1]; + cel.x = m_celHili.x + x; + cel.y = m_celHili.y + y; + rank = GetHiliRankBlupi (i); + if (IsFreeCelHili (cel, rank)) + m_iconHili[1 + x][1 + y] = ICON_HILI_ANY; + else + m_iconHili[1 + x][1 + y] = ICON_HILI_ERR; + } + } + else + m_iconHili[1][1] = ICON_HILI_ERR; + + m_celOutline1.x = (m_celHili.x / 2) * 2; + m_celOutline1.y = (m_celHili.y / 2) * 2; + if ( + GetObject (m_celOutline1, channel, icon) && channel == CHOBJECT && + (icon == 14 // métal ? + || icon == 36 // planches ? + || icon == 44 // pierres ? + || icon == 60 // tomates ? + || icon == 64 // oeufs ? + || icon == 80 // bouteille ? + || icon == 82 // fleurs ? + || icon == 84 // fleurs ? + || icon == 95 // fleurs ? + || icon == 85 // dynamite ? + || icon == 92 // poison ? + || icon == 93 // piège ? + || icon == 123 // fer ? + || icon == 125)) // mine ? + { + if (m_celHili.x % 2 == 0 || m_celHili.y % 2 == 0) + m_celOutline1.x = -1; + } + m_celOutline2 = m_celOutline1; + } + } + } + + if (action == 1) // construction d'une cellule 1x1 ? + { + m_celHili = ConvPosToCel (pos); + + m_iconHili[1][1] = ICON_HILI_BUILD; // action + } + + if (action == 2) // construction d'une cellule 2x2 ? + { + m_celHili = ConvPosToCel2 (pos); + + m_iconHili[1][1] = ICON_HILI_BUILD; // action + m_iconHili[2][1] = ICON_HILI_BUILD; + m_iconHili[1][2] = ICON_HILI_BUILD; + m_iconHili[2][2] = ICON_HILI_BUILD; + } +} + +// Marque la cellule visée par la souris pour un bouton donné. + +void +CDecor::CelHiliButton (Point cel, Sint32 button) +{ + Point celOutline1, celOutline2; + + CelOkForAction ( + cel, table_actions[button], m_rankBlupiHili, m_iconHili, celOutline1, + celOutline2); + + if ( + button == BUTTON_ABAT || button == BUTTON_ABATn || button == BUTTON_ROC || + button == BUTTON_ROCn || button == BUTTON_WALL || button == BUTTON_TOWER || + button == BUTTON_PALIS || button == BUTTON_BRIDGE || + button == BUTTON_CULTIVE || button == BUTTON_DEPOSE || + button == BUTTON_LABO || button == BUTTON_FLOWER || + button == BUTTON_FLOWERn || button == BUTTON_DYNAMITE || + button == BUTTON_BOAT || button == BUTTON_DJEEP || + button == BUTTON_DARMOR || button == BUTTON_FLAG || + button == BUTTON_EXTRAIT || button == BUTTON_FABJEEP || + button == BUTTON_MAKEARMOR || button == BUTTON_FABMINE || + button == BUTTON_FABDISC || + (button >= BUTTON_BUILD1 && button <= BUTTON_BUILD6)) + { + m_celHili.x = (cel.x / 2) * 2; + m_celHili.y = (cel.y / 2) * 2; + } + else + m_celHili = cel; +} + +// Marque la cellule visée par la souris pour une répétition donnée. + +void +CDecor::CelHiliRepeat (Sint32 list) +{ + Sint32 rank, button, x, y, i; + Point cel; + + for (x = 0; x < 4; x++) + { + for (y = 0; y < 4; y++) + m_iconHili[x][y] = -1; + } + + if (m_nbBlupiHili != 1) + return; + rank = m_rankBlupiHili; + + i = m_blupi[rank].repeatLevelHope - list; + if (i < 0 || i > m_blupi[rank].repeatLevelHope) + return; + + button = m_blupi[rank].listButton[i]; + if ( + button == BUTTON_ABAT || button == BUTTON_ABATn || button == BUTTON_ROC || + button == BUTTON_ROCn || button == BUTTON_WALL || button == BUTTON_TOWER || + button == BUTTON_PALIS || button == BUTTON_BRIDGE || + button == BUTTON_CULTIVE || button == BUTTON_DEPOSE || + button == BUTTON_LABO || button == BUTTON_FLOWER || + button == BUTTON_FLOWERn || button == BUTTON_DYNAMITE || + button == BUTTON_BOAT || button == BUTTON_DJEEP || + button == BUTTON_DARMOR || button == BUTTON_FLAG || + button == BUTTON_EXTRAIT || button == BUTTON_FABJEEP || + button == BUTTON_MAKEARMOR || button == BUTTON_FABMINE || + button == BUTTON_FABDISC || + (button >= BUTTON_BUILD1 && button <= BUTTON_BUILD6)) + { + m_iconHili[1][1] = ICON_HILI_OP; // action + m_iconHili[2][1] = ICON_HILI_OP; // action + m_iconHili[1][2] = ICON_HILI_OP; // action + m_iconHili[2][2] = ICON_HILI_OP; // action + + cel = m_blupi[rank].listCel[i]; + cel.x = (cel.x / 2) * 2; + cel.y = (cel.y / 2) * 2; + } + else + { + m_iconHili[1][1] = ICON_HILI_OP; // action + + cel = m_blupi[rank].listCel[i]; + } + m_celHili = cel; +} + +// Retourne l'identificateur du texte correspondant à +// l'objet ou au blupi visé par la souris. + +const char * +CDecor::GetResHili (Point posMouse) +{ + Sint32 icon; + + // The `corner == true` values are corresponding to the objects + // positionned at the bottom/right corner of the cell. + struct object_t { + bool corner; + const char * text; + }; + + static const std::unordered_map tableObject = { + {6, {false, translate ("Tree")}}, + {7, {false, translate ("Tree")}}, + {8, {false, translate ("Tree")}}, + {9, {false, translate ("Tree")}}, + {10, {false, translate ("Tree")}}, + {11, {false, translate ("Tree")}}, + {12, {false, translate ("Enemy rocket")}}, + {14, {false, translate ("Platinium")}}, + {16, {true, translate ("Armour")}}, + {17, {false, translate ("Enemy construction")}}, + {18, {false, translate ("Enemy construction")}}, + {20, {false, translate ("Wall")}}, + {21, {false, translate ("Wall")}}, + {22, {false, translate ("Wall")}}, + {23, {false, translate ("Wall")}}, + {24, {false, translate ("Wall")}}, + {25, {false, translate ("Wall")}}, + {26, {false, translate ("Wall")}}, + {27, {false, translate ("Protection tower")}}, + {28, {false, translate ("Laboratory")}}, + {29, {false, translate ("Laboratory")}}, + {30, {false, translate ("Tree trunks")}}, + {31, {false, translate ("Tree trunks")}}, + {32, {false, translate ("Tree trunks")}}, + {33, {false, translate ("Tree trunks")}}, + {34, {false, translate ("Tree trunks")}}, + {35, {false, translate ("Tree trunks")}}, + {36, {true, translate ("Planks")}}, + {37, {false, translate ("Rocks")}}, + {38, {false, translate ("Rocks")}}, + {39, {false, translate ("Rocks")}}, + {40, {false, translate ("Rocks")}}, + {41, {false, translate ("Rocks")}}, + {42, {false, translate ("Rocks")}}, + {43, {false, translate ("Rocks")}}, + {44, {true, translate ("Stones")}}, + {45, {false, translate ("Fire")}}, + {46, {false, translate ("Fire")}}, + {47, {false, translate ("Fire")}}, + {48, {false, translate ("Fire")}}, + {49, {false, translate ("Fire")}}, + {50, {false, translate ("Fire")}}, + {51, {false, translate ("Fire")}}, + {52, {false, translate ("Fire")}}, + {57, {true, translate ("Tomatoes")}}, + {58, {true, translate ("Tomatoes")}}, + {59, {true, translate ("Tomatoes")}}, + {60, {true, translate ("Tomatoes")}}, + {61, {false, translate ("Garden shed")}}, + {62, {false, translate ("Garden shed")}}, + {63, {true, translate ("Eggs")}}, + {64, {false, translate ("Eggs")}}, + {65, {false, translate ("Palisade")}}, + {66, {false, translate ("Palisade")}}, + {67, {false, translate ("Palisade")}}, + {68, {false, translate ("Palisade")}}, + {69, {false, translate ("Palisade")}}, + {70, {false, translate ("Palisade")}}, + {71, {false, translate ("Palisade")}}, + {72, {false, translate ("Bridge")}}, + {73, {false, translate ("Bridge")}}, + {80, {true, translate ("Medical potion")}}, + {81, {false, translate ("Flowers")}}, + {82, {true, translate ("Bunch of flowers")}}, + {83, {false, translate ("Flowers")}}, + {84, {true, translate ("Bunch of flowers")}}, + {85, {true, translate ("Dynamite")}}, + {86, {true, translate ("Dynamite")}}, + {87, {true, translate ("Dynamite")}}, + {92, {true, translate ("Poison")}}, + {93, {true, translate ("Sticky trap")}}, + {94, {false, translate ("Flowers")}}, + {95, {true, translate ("Bunch of flowers")}}, + {96, {true, translate ("Trapped enemy")}}, + {97, {true, translate ("Trapped enemy")}}, + {98, {true, translate ("Trapped enemy")}}, + {99, {false, translate ("Enemy construction")}}, + {100, {false, translate ("Enemy construction")}}, + {101, {false, translate ("Enemy construction")}}, + {102, {false, translate ("Enemy construction")}}, + {103, {false, translate ("Enemy construction")}}, + {104, {false, translate ("Enemy construction")}}, + {105, {false, translate ("Enemy construction")}}, + {106, {false, translate ("Enemy construction")}}, + {107, {false, translate ("Enemy construction")}}, + {108, {false, translate ("Enemy construction")}}, + {109, {false, translate ("Enemy construction")}}, + {110, {false, translate ("Enemy construction")}}, + {111, {false, translate ("Enemy construction")}}, + {112, {false, translate ("Enemy construction")}}, + {113, {false, translate ("Blupi's house")}}, + {114, {true, translate ("Trapped enemy")}}, + {115, {false, translate ("Enemy construction")}}, + {116, {false, translate ("Enemy construction")}}, + {117, {true, translate ("Boat")}}, + {118, {true, translate ("Jeep")}}, + {119, {false, translate ("Workshop")}}, + {120, {false, translate ("Workshop")}}, + {121, {false, translate ("Mine")}}, + {122, {false, translate ("Mine")}}, + {123, {true, translate ("Iron")}}, + {124, {false, translate ("Flag")}}, + {125, {true, translate ("Time bomb")}}, + {126, {false, translate ("Mine")}}, + {127, {true, translate ("Time bomb")}}, + {128, {false, translate ("Enemy construction")}}, + {129, {false, translate ("Enemy construction")}}, + {130, {true, translate ("Trapped enemy")}}, + }; + + static const std::unordered_map tableFloor = { + {1, {false, translate ("Normal ground")}}, + {2, {false, translate ("Bank")}}, + {3, {false, translate ("Bank")}}, + {4, {false, translate ("Bank")}}, + {5, {false, translate ("Bank")}}, + {6, {false, translate ("Bank")}}, + {7, {false, translate ("Bank")}}, + {8, {false, translate ("Bank")}}, + {9, {false, translate ("Bank")}}, + {10, {false, translate ("Bank")}}, + {11, {false, translate ("Bank")}}, + {12, {false, translate ("Bank")}}, + {13, {false, translate ("Bank")}}, + {14, {false, translate ("Water")}}, + {15, {false, translate ("Paving stones")}}, + {16, {false, translate ("Paving stones")}}, + {17, {false, translate ("Striped paving stones")}}, + {18, {false, translate ("Ice")}}, + {19, {false, translate ("Burnt ground")}}, + {20, {false, translate ("Inflammable ground")}}, + {21, {false, translate ("Miscellaneous ground")}}, + {22, {false, translate ("Miscellaneous ground")}}, + {23, {false, translate ("Miscellaneous ground")}}, + {24, {false, translate ("Miscellaneous ground")}}, + {25, {false, translate ("Miscellaneous ground")}}, + {26, {false, translate ("Miscellaneous ground")}}, + {27, {false, translate ("Miscellaneous ground")}}, + {28, {false, translate ("Miscellaneous ground")}}, + {29, {false, translate ("Miscellaneous ground")}}, + {30, {false, translate ("Miscellaneous ground")}}, + {31, {false, translate ("Miscellaneous ground")}}, + {32, {false, translate ("Miscellaneous ground")}}, + {33, {false, translate ("Sterile ground")}}, + {34, {false, translate ("Miscellaneous ground")}}, + {35, {false, translate ("Miscellaneous ground")}}, + {36, {false, translate ("Miscellaneous ground")}}, + {37, {false, translate ("Miscellaneous ground")}}, + {38, {false, translate ("Miscellaneous ground")}}, + {39, {false, translate ("Miscellaneous ground")}}, + {40, {false, translate ("Miscellaneous ground")}}, + {41, {false, translate ("Miscellaneous ground")}}, + {42, {false, translate ("Miscellaneous ground")}}, + {43, {false, translate ("Miscellaneous ground")}}, + {44, {false, translate ("Miscellaneous ground")}}, + {45, {false, translate ("Miscellaneous ground")}}, + {46, {false, translate ("Sterile ground")}}, + {47, {false, translate ("Sterile ground")}}, + {48, {false, translate ("Sterile ground")}}, + {49, {false, translate ("Normal ground")}}, + {50, {false, translate ("Normal ground")}}, + {51, {false, translate ("Normal ground")}}, + {52, {false, translate ("Incubator")}}, + {53, {false, translate ("Incubator")}}, + {54, {false, translate ("Incubator")}}, + {55, {false, translate ("Incubator")}}, + {56, {false, translate ("Incubator")}}, + {57, {false, translate ("Normal ground")}}, + {58, {false, translate ("Inflammable ground")}}, + {59, {false, translate ("Bridge")}}, + {60, {false, translate ("Bridge")}}, + {61, {false, translate ("Bridge")}}, + {62, {false, translate ("Bridge")}}, + {63, {false, translate ("Bridge")}}, + {64, {false, translate ("Bridge")}}, + {65, {false, translate ("Enemy ground")}}, + {66, {false, translate ("Miscellaneous ground")}}, + {67, {false, translate ("Enemy ground")}}, + {68, {false, translate ("Water")}}, + {69, {false, translate ("Water")}}, + {70, {false, translate ("Water")}}, + {71, {false, translate ("Sterile ground")}}, + {78, {false, translate ("Miscellaneous ground")}}, + {79, {false, translate ("Miscellaneous ground")}}, + {80, {false, translate ("Teleporter")}}, + {81, {false, translate ("Teleporter")}}, + {82, {false, translate ("Teleporter")}}, + {83, {false, translate ("Teleporter")}}, + {84, {false, translate ("Teleporter")}}, + }; + + if (m_bHideTooltips) + return nullptr; // rien si menu présent + + if ( + posMouse.x < POSDRAWX || posMouse.x > POSDRAWX + DIMDRAWX || + posMouse.y < POSDRAWY || posMouse.y > POSDRAWY + DIMDRAWY) + return nullptr; + + if (m_celHili.x != -1) + { + if (m_rankHili != -1) // blupi visé ? + { + switch (m_blupi[m_rankHili].perso) + { + case 0: // blupi ? + if (m_blupi[m_rankHili].energy <= MAXENERGY / 4) + return gettext ("Tired Blupi"); + if (m_blupi[m_rankHili].bMalade) + return gettext ("Sick Blupi"); + return gettext ("Blupi"); + case 1: // spider ? + return gettext ("Spider"); + case 2: // virus ? + return gettext ("Virus"); + case 3: // tracks ? + return gettext ("Bulldozer"); + case 4: // robot ? + return gettext ("Master robot"); + case 5: // bombe ? + return gettext ("Bouncing bomb"); + case 7: // electro ? + return gettext ("Electrocutor"); + case 8: // disciple ? + return gettext ("Helper robot"); + } + + return nullptr; + } + + icon = m_decor[m_celHili.x / 2][m_celHili.y / 2].objectIcon; + if (icon != -1) + { + const auto obj = tableObject.find (icon); + if (obj != tableObject.end ()) + { + if (!obj->second.corner) + return gettext (obj->second.text); + + if (m_celHili.x % 2 && m_celHili.y % 2) + return gettext (obj->second.text); + } + } + + icon = m_decor[m_celHili.x / 2][m_celHili.y / 2].floorIcon; + if (icon != -1) + { + const auto obj = tableFloor.find (icon); + if (obj != tableFloor.end ()) + return gettext (obj->second.text); + } + } + + return nullptr; +} + +// Indique si le menu est présent et qu'il faut cacher +// les tooltips du décor. + +void +CDecor::HideTooltips (bool bHide) +{ + m_bHideTooltips = bHide; +} + +// Modifie l'origine supérieure/gauche du décor. + +void +CDecor::SetCorner (Point corner, bool bCenter) +{ + if (bCenter) + { + corner.x -= 10; + corner.y -= 2; + } + + if (corner.x < -8) + corner.x = -8; + if (corner.x > MAXCELX - 12) + corner.x = MAXCELX - 12; + if (corner.y < -2) + corner.y = -2; + if (corner.y > MAXCELY - 4) + corner.y = MAXCELY - 4; + + m_celCorner = corner; + m_bGroundRedraw = true; // faudra redessiner les sols + m_celHili.x = -1; + m_textLastPos.x = -1; // tooltips plus lavable ! +} + +Point +CDecor::GetCorner () +{ + return m_celCorner; +} + +Point +CDecor::GetHome () +{ + return m_celHome; +} + +// Mémoirise une position pendant le jeu. + +void +CDecor::MemoPos (Sint32 rank, bool bRecord) +{ + Point pos; + + pos.x = LXIMAGE () / 2; + pos.y = LYIMAGE () / 2; + + if (rank < 0 || rank >= 4) + return; + + if (bRecord) + { + m_pSound->PlayImage (SOUND_CLOSE, pos); + m_memoPos[rank] = m_celCorner; + } + else + { + if (m_memoPos[rank].x == 0 && m_memoPos[rank].y == 0) + m_pSound->PlayImage (SOUND_BOING, pos); + else + { + m_pSound->PlayImage (SOUND_GOAL, pos); + SetCorner (m_memoPos[rank], false); + } + } +} + +// Gestion du temps absolu global. + +void +CDecor::SetTime (Sint32 time) +{ + m_time = time; + m_timeConst = time; // vraiment ? + m_timeFlipOutline = time; +} + +Sint32 +CDecor::GetTime () +{ + return m_time; +} + +// Gestion de la musique midi. + +void +CDecor::SetMusic (Sint32 music) +{ + m_music = music; +} + +Sint32 +CDecor::GetMusic () +{ + return m_music; +} + +// Gestion de la difficulté. + +void +CDecor::SetSkill (Sint32 skill) +{ + m_skill = skill; +} + +Sint32 +CDecor::GetSkill () +{ + return m_skill; +} + +// Gestion de la région. +// 0 = normal +// 1 = palmier +// 2 = hiver +// 3 = sapin + +void +CDecor::SetRegion (Sint32 region) +{ + m_region = region; +} + +Sint32 +CDecor::GetRegion () +{ + return m_region; +} + +// Gestion des infos. + +void +CDecor::SetInfoMode (bool bInfo) +{ + m_bInfo = bInfo; + m_bGroundRedraw = true; // faudra redessiner les sols +} + +bool +CDecor::GetInfoMode () +{ + return m_bInfo; +} + +void +CDecor::SetInfoHeight (Sint32 height) +{ + m_infoHeight = height; + m_bGroundRedraw = true; // faudra redessiner les sols +} + +Sint32 +CDecor::GetInfoHeight () +{ + if (m_bInfo) + return m_infoHeight; + else + return 0; +} + +// Retourne le pointeur à la liste des boutons existants. + +char * +CDecor::GetButtonExist () +{ + return m_buttonExist; +} + +// Ouvre le buffer pour le undo pendant la construction. + +void +CDecor::UndoOpen () +{ + if (m_pUndoDecor == nullptr) + m_pUndoDecor = + (Cellule *) malloc (sizeof (Cellule) * (MAXCELX / 2) * (MAXCELY / 2)); +} + +// Ferme le buffer pour le undo pendant la construction. + +void +CDecor::UndoClose () +{ + if (m_pUndoDecor != nullptr) + { + free (m_pUndoDecor); + m_pUndoDecor = nullptr; + } +} + +// Copie le décor dans le buffer pour le undo. + +void +CDecor::UndoCopy () +{ + UndoOpen (); // ouvre le buffer du undo si nécessaire + + if (m_pUndoDecor != nullptr) + memcpy ( + m_pUndoDecor, &m_decor, sizeof (Cellule) * (MAXCELX / 2) * (MAXCELY / 2)); +} + +// Revient en arrière pour tout le décor. + +void +CDecor::UndoBack () +{ + if (m_pUndoDecor != nullptr) + { + memcpy ( + &m_decor, m_pUndoDecor, sizeof (Cellule) * (MAXCELX / 2) * (MAXCELY / 2)); + UndoClose (); + m_bGroundRedraw = true; + } +} + +// Indique s'il est possible d'effectuer un undo. + +bool +CDecor::IsUndo () +{ + return (m_pUndoDecor != nullptr); +} + +void +CDecor::InvalidateGrounds () +{ + m_bGroundRedraw = true; +} diff --git a/src/decor.h b/src/decor.h new file mode 100644 index 0000000..8011066 --- /dev/null +++ b/src/decor.h @@ -0,0 +1,575 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include "def.h" +#include "pixmap.h" +#include "sound.h" +#include + +#define MAXENERGY 4000 +#define MAXFIRE 400 + +// clang-format off +#define ICON_HILI_STAT 112 +#define ICON_HILI_SEL 113 +#define ICON_HILI_ANY 114 +#define ICON_HILI_OP 115 +#define ICON_HILI_GO 117 +#define ICON_HILI_BUILD 118 +#define ICON_HILI_ERR 119 +// clang-format on + +// Descripteur d'une cellule du décor. +typedef struct { + Sint16 floorChannel; + Sint16 floorIcon; + Sint16 objectChannel; + Sint16 objectIcon; + Sint16 fog; // brouillard + Sint16 rankMove; // rang dans m_move + Sint16 workBlupi; // rang du blupi travaillant ici + Sint16 fire; +} Cellule; +// Cette structure doit être la plus petite possible, car +// il en existe un tableau de 100x100 = 10'000 cellules ! + +typedef struct : Cellule { + bool flagged; // when a flag has been built for the iron +} CellMem; + +// Descripteur d'un blupi animé. +#define MAXBLUPI 100 +#define MAXUSED 50 +#define MAXLIST 10 + +typedef struct { + Sint32 bExist; // true -> utilisé + Sint32 bHili; // true -> sélectionné + + Sint16 perso; // personnage, voir (*) + + Sint16 goalAction; // action (Sint32 terme) + Sint16 goalPhase; // phase (Sint32 terme) + Point goalCel; // cellule visée (Sint32 terme) + Point passCel; // cellule tranversante + + Sint16 energy; // énergie restante + + Point cel; // cellule actuelle + Point destCel; // cellule destination + Sint16 action; // action en cours + Sint16 aDirect; // direction actuelle + Sint16 sDirect; // direction souhaitée + + Point pos; // position relative à partir de la cellule + Sint16 posZ; // déplacement z + Sint16 channel; + Sint16 lastIcon; + Sint16 icon; + Sint16 phase; // phase dans l'action + Sint16 step; // pas global + Sint16 interrupt; // 0=prioritaire, 1=normal, 2=misc + Sint16 clipLeft; + + Sint32 nbUsed; // nb de points déjà visités + char nextRankUsed; + Point posUsed[MAXUSED]; + char rankUsed[MAXUSED]; + + Sint16 takeChannel; // objet transporté + Sint16 takeIcon; + + Point fix; // point fixe (cultive, pont) + + Sint16 jaugePhase; + Sint16 jaugeMax; + Sint16 stop; // 1 -> devra stopper + Sint16 bArrow; // true -> flèche en dessus de blupi + Sint16 bRepeat; // true -> répète l'action + Sint16 nLoop; // nb de boucles pour GOAL_OTHERLOOP + Sint16 cLoop; // boucle en cours + Sint16 vIcon; // icône variable + Point goalHili; // but visé + Sint16 bMalade; // true -> blupi malade + Sint16 bCache; // true -> caché (pas dessiné) + Sint16 vehicule; // véhicule utilisé par blupi, voir (**) + char busyCount; + char busyDelay; + char clicCount; + char clicDelay; + char reserve2[2]; + Sint16 listButton[MAXLIST]; + Point listCel[MAXLIST]; + Sint16 listParam[MAXLIST]; + Sint16 repeatLevelHope; + Sint16 repeatLevel; + Sint16 reserve3[88]; +} Blupi; + +// (*) Personnages : +// 0 -> blupi +// 1 -> araignée +// 2 -> virus +// 3 -> tracks +// 4 -> robot +// 5 -> bombe +// 6 -> détonnateur de mine (invisible) +// 7 -> électro +// 8 -> disciple (robot2) + +// (**) Véhicule : +// 0 -> à pied +// 1 -> en bateau +// 2 -> en jeep +// 3 -> armure + +// Descripteur d'un décor animé. +#define MAXMOVE 100 +#define MOVEICONNB 1000 + +typedef struct { + Sint32 bExist; // true -> utilisé + + Point cel; // cellule du décor + Sint16 rankBlupi; // blupi travaillant ici + + Sint32 bFloor; // true -> floor, false -> object + Sint16 channel; + Sint16 icon; + Sint16 maskChannel; + Sint16 maskIcon; + Sint16 phase; // phase pour pMoves ou pIcon + Sint16 rankMoves; // *nb,dx,dy,... + Sint16 rankIcons; // *nb,i,i,... + + Sint16 total; // nb total d'étapes + Sint16 delai; // délai entre deux pas + Sint16 stepY; // pas vertical *100 + + Sint16 cTotal; + Sint16 cDelai; +} Move; + +#define MAXLASTDRAPEAU 50 + +class CDecor +{ +public: + CDecor (); + ~CDecor (); + + // Arrange.cpp + void ArrangeFloor (Point cel); + void ArrangeMur (Point cel, Sint32 & icon, Sint32 index); + void ArrangeBuild (Point cel, Sint32 & channel, Sint32 & icon); + void ArrangeObject (Point cel); + + bool ArrangeFillTestFloor (Point cel1, Point cel2); + bool ArrangeFillTest (Point pos); + void ArrangeFillPut (Point pos, Sint32 channel, Sint32 icon); + void ArrangeFillSearch (Point pos); + void ArrangeFill (Point pos, Sint32 channel, Sint32 icon, bool bFloor); + + void ArrangeBlupi (); + + // Obstacle.cpp + void SearchFloor (Sint32 rank, Sint32 icon, Point cel, Sint32 * pBits); + void SearchObject (Sint32 rank, Sint32 icon, Point cel, Sint32 * pBits); + void AjustFloor (Sint32 rank, Sint32 icon, Point cel, Sint32 * pBits); + void AjustObject (Sint32 rank, Sint32 icon, Point cel, Sint32 * pBits); + bool IsFreeDirect (Point cel, Sint32 direct, Sint32 rank); + bool IsFreeCelObstacle (Point cel); + bool IsFreeCelFloor (Point cel, Sint32 rank); + bool IsFreeCelGo (Point cel, Sint32 rank); + bool IsFreeCelHili (Point cel, Sint32 rank); + bool IsFreeCel (Point cel, Sint32 rank); + bool IsFreeCelDepose (Point cel, Sint32 rank); + bool + IsFreeCelEmbarque (Point cel, Sint32 rank, Sint32 & action, Point & limit); + bool + IsFreeCelDebarque (Point cel, Sint32 rank, Sint32 & action, Point & limit); + bool IsFreeJump (Point cel, Sint32 direct, Sint32 rank, Sint32 & action); + bool IsFreeGlisse (Point cel, Sint32 direct, Sint32 rank, Sint32 & action); + Sint32 DirectSearch (Point cel, Point goal); + void FlushUsed (Sint32 rank); + void AddUsedPos (Sint32 rank, Point pos); + bool IsUsedPos (Sint32 rank, Point pos); + bool SearchBestBase ( + Sint32 rank, Sint32 & action, Point & newCel, Sint32 & direct); + bool SearchBestPass (Sint32 rank, Sint32 & action); + bool IsWorkableObject (Point cel, Sint32 rank); + bool SearchOtherObject ( + Sint32 rank, Point initCel, Sint32 action, Sint32 distMax, Sint32 channel, + Sint32 firstIcon1, Sint32 lastIcon1, Sint32 firstIcon2, Sint32 lastIcon2, + Point & foundCel, Sint32 & foundIcon); + bool SearchOtherDrapeau ( + Sint32 rank, Point initCel, Sint32 distMax, Point & foundCel, + Sint32 & foundIcon); + bool SearchOtherBateau ( + Sint32 rank, Point initCel, Sint32 distMax, Point & foundCel, + Sint32 & foundIcon); + bool IsSpiderObject (Sint32 icon); + bool SearchSpiderObject ( + Sint32 rank, Point initCel, Sint32 distMax, Point & foundCel, + Sint32 & foundIcon); + bool IsTracksObject (Sint32 icon); + bool SearchTracksObject ( + Sint32 rank, Point initCel, Sint32 distMax, Point & foundCel, + Sint32 & foundIcon); + bool IsRobotObject (Sint32 icon); + bool SearchRobotObject ( + Sint32 rank, Point initCel, Sint32 distMax, Point & foundCel, + Sint32 & foundIcon, Sint32 & foundAction); + bool IsBombeObject (Sint32 icon); + bool SearchBombeObject ( + Sint32 rank, Point initCel, Sint32 distMax, Point & foundCel, + Sint32 & foundIcon); + bool SearchElectroObject ( + Sint32 rank, Point initCel, Sint32 distMax, Point & foundCel, + Sint32 & foundIcon); + bool IsUsineBuild (Sint32 rank, Point cel); + bool IsUsineFree (Sint32 rank, Point cel); + bool IsFireCel (Point cel); + bool IsVirusCel (Point cel); + Errors IsBuildPont (Point & cel, Sint32 & iconBuild); + bool IsBuildBateau (Point cel, Sint32 & direct); + void InitDrapeau (); + void AddDrapeau (Point cel); + void SubDrapeau (Point cel); + bool TestDrapeau (Point cel); + + // DecBlupi.cpp + void BlupiFlush (); + Sint32 BlupiCreate ( + Point cel, Sint32 action, Sint32 direct, Sint32 perso, Sint32 energy); + bool BlupiDelete (Point cel, Sint32 perso = -1); + void BlupiDelete (Sint32 rank); + void BlupiKill (Sint32 exRank, Point cel, Sint32 type); + bool BlupiIfExist (Sint32 rank); + void BlupiCheat (Sint32 cheat); + void BlupiActualise (Sint32 rank); + void BlupiAdaptIcon (Sint32 rank); + void BlupiPushFog (Sint32 rank); + void BlupiSound (Sint32 rank, Sounds sound, Point pos, bool bStop = false); + void BlupiInitAction (Sint32 rank, Sint32 action, Sint32 direct = -1); + void BlupiChangeAction (Sint32 rank, Sint32 action, Sint32 direct = -1); + void ListFlush (Sint32 rank); + Sint32 ListGetParam (Sint32 rank, Buttons button, Point cel); + bool ListPut (Sint32 rank, Buttons button, Point cel, Point cMem); + void ListRemove (Sint32 rank); + Sint32 ListSearch ( + Sint32 rank, Buttons button, Point cel, const char *& textForButton); + bool RepeatAdjust ( + Sint32 rank, Sint32 button, Point & cel, Point & cMem, Sint32 param, + Sint32 list); + void GoalStart (Sint32 rank, Sint32 action, Point cel); + bool GoalNextPhase (Sint32 rank); + void SetTotalTime (Sint32 total); + Sint32 GetTotalTime (); + void GoalInitJauge (Sint32 rank); + void GoalInitPassCel (Sint32 rank); + void GoalAdjustCel (Sint32 rank, Sint32 & x, Sint32 & y); + bool GoalNextOp (Sint32 rank, Sint16 * pTable); + void GoalUnwork (Sint32 rank); + void GoalStop (Sint32 rank, bool bError = false, bool bSound = true); + bool BlupiIsGoalUsed (Point cel); + void BlupiStartStopRayon (Sint32 rank, Point startCel, Point endCel); + bool BlupiRotate (Sint32 rank); + bool BlupiNextAction (Sint32 rank); + void BlupiNextGoal (Sint32 rank); + void BlupiStep (bool bFirst); + void BlupiGetRect (Sint32 rank, Rect & rect); + Sint32 GetTargetBlupi (Point pos); + void BlupiDeselect (); + void BlupiDeselect (Sint32 rank); + void BlupiSetArrow (Sint32 rank, bool bArrow); + void InitOutlineRect (); + void BlupiHiliDown (Point pos, bool bAdd = false); + void BlupiHiliMove (Point pos); + void BlupiHiliUp (Point pos); + void BlupiDrawHili (); + Buttons GetDefButton (Point cel); + bool BlupiGoal (Sint32 rank, Buttons button, Point cel, Point cMem); + void BlupiGoal (Point cel, Buttons button); + void BlupiDestCel (Sint32 rank); + bool IsTracksHere (Point cel, bool bSkipInMove); + bool IsBlupiHereEx (Point cel1, Point cel2, Sint32 exRank, bool bSkipInMove); + bool IsBlupiHereEx (Point cel, Sint32 exRank, bool bSkipInMove); + bool IsBlupiHere (Point cel, bool bSkipInMove); + bool IsBlupiHere (Point cel, Sint32 direct, bool bSkipInMove); + void GetLevelJauge (Sint32 * pLevels, Sint32 * pTypes); + bool IsWorkBlupi (Sint32 rank); + void BlupiGetButtons ( + Point pos, Sint32 & nb, Buttons * pButtons, Errors * pErrors, + std::unordered_map & texts, Sint32 & perso); + void TerminatedInit (); + Sint32 IsTerminated (); + Term * GetTerminated (); + + // DecMove.cpp + bool CanBurn (Point cel); + void MoveFlush (); + Sint32 MoveMaxFire (); + void MoveFixInit (); + bool MoveCreate ( + Point cel, Sint32 rankBlupi, bool bFloor, Sint32 channel, Sint32 icon, + Sint32 maskChannel, Sint32 maskIcon, Sint32 total, Sint32 delai, + Sint32 stepY, bool bMisc = false, bool bNotIfExist = false); + bool MoveAddMoves (Point cel, Sint32 rankMoves); + bool MoveAddIcons (Point cel, Sint32 rankIcons, bool bContinue = false); + bool MoveStartFire (Point cel); + void MoveProxiFire (Point cel); + void MoveFire (Sint32 rank); + void MoveStep (bool bFirst); + void MoveFinish (Point cel); + void MoveFinish (Sint32 rankBlupi); + bool MoveIsUsed (Point cel); + bool MoveGetObject (Point cel, Sint32 & channel, Sint32 & icon); + bool MovePutObject (Point cel, Sint32 channel, Sint32 icon); + + // DecIO.cpp + bool Write (Sint32 rank, bool bUser, Sint32 world, Sint32 time, Sint32 total); + bool + Read (Sint32 rank, bool bUser, Sint32 & world, Sint32 & time, Sint32 & total); + bool FileExist ( + Sint32 rank, bool bUser, Sint32 & world, Sint32 & time, Sint32 & total); + void Flush (); + + // DecMap.cpp + void MapInitColors (); + Point ConvCelToMap (Point cel); + Point ConvMapToCel (Point pos); + bool MapMove (Point pos); + void MapPutCel (Point pos); + bool GenerateMap (); + + // DecStat.cpp + void StatisticInit (); + void StatisticUpdate (); + Sint32 StatisticGetBlupi (); + Sint32 StatisticGetFire (); + void StatisticDraw (); + void GenerateStatictic (); + bool StatisticDown (Point pos); + bool StatisticMove (Point pos, bool & disable); + bool StatisticUp (Point pos); + Sint32 StatisticDetect (Point pos, bool & disable); + + // Chemin.cpp + void CheminMemPos (Sint32 exRank); + bool CheminTestPos (Point pos, Sint32 & rank); + Sint32 CheminARebours (Sint32 rank); + void CheminFillTerrain (Sint32 rank); + bool CheminTestDirection ( + Sint32 rank, Sint32 pos, Sint32 dir, Sint32 & next, Sint32 & ampli, + Sint32 & cout, Sint32 & action); + bool CheminCherche (Sint32 rank, Sint32 & action); + bool IsCheminFree (Sint32 rank, Point dest, Sint32 button); + + // Decor.cpp + void FixShifting (Sint32 & nbx, Sint32 & nby, Point & iCel, Point & iPos); + void SetShiftOffset (Point offset); + Point ConvCelToPos (Point cel); + Point ConvPosToCel (Point pos, bool bMap = false); + Point ConvPosToCel2 (Point pos); + + void Create (CSound * pSound, CPixmap * pPixmap); + void Init (Sint32 channel, Sint32 icon); + void InitAfterBuild (); + void ResetHili (); + bool LoadImages (); + void ClearFog (); + void ClearFire (); + void SetBuild (bool bBuild); + void EnableFog (bool bEnable); + bool GetInvincible (); + void SetInvincible (bool bInvincible); + bool GetSuper (); + void SetSuper (bool bSuper); + void FlipOutline (); + bool PutFloor (Point cel, Sint32 channel, Sint32 icon); + bool PutObject (Point cel, Sint32 channel, Sint32 icon); + bool GetFloor (Point cel, Sint32 & channel, Sint32 & icon); + bool GetObject (Point cel, Sint32 & channel, Sint32 & icon); + bool SetFire (Point cel, bool bFire); + + void SetCorner (Point corner, bool bCenter = false); + Point GetCorner (); + Point GetHome (); + void MemoPos (Sint32 rank, bool bRecord); + + void SetTime (Sint32 time); + Sint32 GetTime (); + + void SetMusic (Sint32 music); + Sint32 GetMusic (); + + void SetSkill (Sint32 skill); + Sint32 GetSkill (); + + void SetRegion (Sint32 region); + Sint32 GetRegion (); + + void SetInfoMode (bool bInfo); + bool GetInfoMode (); + void SetInfoHeight (Sint32 height); + Sint32 GetInfoHeight (); + + char * GetButtonExist (); + + void BuildPutBlupi (); + void BuildMoveFloor (Sint32 x, Sint32 y, Point pos, Sint32 rank); + void BuildMoveObject (Sint32 x, Sint32 y, Point pos, Sint32 rank); + void BuildGround (Rect clip); + void Build (Rect clip, Point posMouse); + void NextPhase (Sint32 mode); + + Sint32 CountFloor (Sint32 channel, Sint32 icon); + Errors CelOkForAction ( + Point cel, Sint32 action, Sint32 rank, Sint32 icons[4][4], + Point & celOutline1, Point & celOutline2); + Errors CelOkForAction (Point cel, Sint32 action, Sint32 rank); + Sint32 GetHiliRankBlupi (Sint32 nb); + void CelHili (Point pos, Sint32 action); + void CelHiliButton (Point cel, Sint32 button); + void CelHiliRepeat (Sint32 list); + const char * GetResHili (Point posMouse); + void HideTooltips (bool bHide); + + void UndoOpen (); + void UndoClose (); + void UndoCopy (); + void UndoBack (); + bool IsUndo (); + + void InvalidateGrounds (); + +protected: + bool GetSeeBits (Point cel, char * pBits, Sint32 index); + Sint32 GetSeeIcon (char * pBits, Sint32 index); + +protected: + CSound * m_pSound; + CPixmap * m_pPixmap; + Cellule * m_pUndoDecor; + Cellule m_decor[MAXCELX / 2][MAXCELY / 2]; + CellMem m_decorMem[MAXCELX / 2][MAXCELY / 2]; + Sint16 m_rankBlupi[MAXCELX][MAXCELY]; + Blupi m_blupi[MAXBLUPI]; + Move m_move[MAXMOVE]; + Point m_celCorner; // cellule sup/gauche + Point m_celHome; // pour touche Home + Point m_celHili; + Point m_celOutline1; + Point m_celOutline2; + Point m_shiftOffset; + Sint32 m_iconHili[4][4]; + Sint32 m_rankHili; // rang du blupi visé + bool m_bHiliRect; + Point m_p1Hili; // coins rectangle de sélection + Point m_p2Hili; + Sint32 m_shiftHili; + Sint32 m_nbBlupiHili; // nb de blupi sélectionnés + Sint32 m_rankBlupiHili; // rang blupi sélectionné + bool m_bFog; // true -> brouillard (jeu) + bool m_bBuild; // true -> construction + bool m_bInvincible; // true -> cheat code + bool m_bSuper; // true -> cheat code + Uint32 m_colors[100]; + Sint32 m_time; // temps relatif global + Sint32 m_timeConst; // temps relatif global constant + Sint32 m_timeFlipOutline; // temps quand basculer mode outline + Sint32 m_totalTime; // temps total passé sur une partie + Sint32 m_phase; // phase pour la carte + Point m_celArrow; // cellule avec flèche + bool m_bOutline; + bool m_bGroundRedraw; + char m_buttonExist[MAXBUTTON]; + Sint32 m_statNb; // nb de statistiques + Sint32 m_statFirst; // première statistique visible + Sint32 m_bStatUp; // flèche up statistique + Sint32 m_bStatDown; // flèche down statistique + Sint32 m_statHili; // statistique survolée + bool m_bStatRecalc; // true -> recalcule les statistiques + Sint32 m_nbStatHach; // nb de hachures + Sint32 m_nbStatHachBlupi; // hachures occupées par blupi + Sint32 m_nbStatHachPlanche; // hachures occupées par planches + Sint32 m_nbStatHachTomate; // hachures occupées par tomates + Sint32 m_nbStatHachMetal; // hachures occupées par métal + Sint32 m_nbStatHachRobot; // hachures occupées par robot + Sint32 m_nbStatHome; // nb de maisons + Sint32 m_nbStatHomeBlupi; // maisons occupées par blupi + Sint32 m_nbStatRobots; // nb d'ennemis + Term m_term; // conditions pour gagner + Sint32 m_winCount; // compteur avant gagné + Sint32 m_winLastHachBlupi; // dernier nombre atteint + Sint32 m_winLastHachPlanche; // dernier nombre atteint + Sint32 m_winLastHachTomate; // dernier nombre atteint + Sint32 m_winLastHachMetal; // dernier nombre atteint + Sint32 m_winLastHachRobot; // dernier nombre atteint + Sint32 m_winLastHome; // dernier nombre atteint + Sint32 m_winLastHomeBlupi; // dernier nombre atteint + Sint32 m_winLastRobots; // dernier nombre atteint + Sint32 m_music; // numéro musique + Sint32 m_region; // numéro région (*) + Sint32 m_lastRegion; // numéro dernière région + Sint32 m_blupiHere; + Point m_lastDrapeau[MAXLASTDRAPEAU]; + bool m_bHideTooltips; // true -> menu présent + char m_text[50]; + Point m_textLastPos; + Sint32 m_textCount; + Sint32 m_skill; + bool m_bInfo; + Sint32 m_infoHeight; + Point m_memoPos[4]; + + Uint8 m_cheminWork[MAXCELX * MAXCELY]; + Sint32 m_cheminNbPos; + Point m_cheminPos[MAXBLUPI * 2]; + Sint32 m_cheminRank[MAXBLUPI * 2]; + + bool m_bFillFloor; + Sint32 m_fillSearchChannel; + Sint32 m_fillSearchIcon; + Sint32 m_fillPutChannel; + Sint32 m_fillPutIcon; + char * m_pFillMap; + + SDL_Surface * m_SurfaceMap; +}; + +// (*) Régions : +// 0 -> normal +// 1 -> palmier +// 2 -> hiver +// 3 -> sapin + +///////////////////////////////////////////////////////////////////////////// + +Point GetCel (Sint32 x, Sint32 y); +Point GetCel (Point cel, Sint32 x, Sint32 y); +bool IsValid (Point cel); +Point GetVector (Sint32 direct); + +extern Sint32 table_multi_goal[]; +extern const Sint16 table_actions[]; diff --git a/src/decstat.cxx b/src/decstat.cxx new file mode 100644 index 0000000..1a6048d --- /dev/null +++ b/src/decstat.cxx @@ -0,0 +1,1061 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "decor.h" +#include "gettext.h" +#include "misc.h" +#include "text.h" + +#define STATNB 12 + +// clang-format off +#define STATBLUPIm 0 +#define STATBLUPIf 1 +#define STATBLUPI 2 +#define STATDISCIPLE 3 +#define STATFEU 27 +#define STATROBOT 28 +#define STATTRACKS 29 +#define STATBOMBE 30 +#define STATARAIGNEE 31 +#define STATVIRUS 32 +#define STATELECTRO 33 +// clang-format on + +typedef struct { + Sint16 bExist; + Sint16 perso; // -1=objet, -2=feu, -3=flèche + Sint16 firstIcon; // négatif si sol + Sint16 lastIcon; // négatif si sol + Sint16 drawIcon; + Sint16 bBigIcon; + const char * text; + Sint16 nb; + Sint16 lastShow; +} Statistic; + +// clang-format off +static Statistic table_statistic[] = +{ + { // STATBLUPIm = 0 + true, + 0, // blupi malade + 0, 0, // + 76, + false, + translate ("Sick Blupi"), + 0, 0, + }, + { // STATBLUPIf = 1 + true, + 0, // blupi fatigué + 0, 0, // + 13, + false, + translate ("Tired Blupi"), + 0, 0, + }, + { // STATBLUPI = 2 + true, + 0, // blupi énergique + 0, 0, // + 14, + false, + translate ("Blupi"), + 0, 0, + }, + { // STATDISCIPLE = 3 + true, + 8, // disciple + 0, 0, // + 85, + false, + translate ("Helper robot"), + 0, 0, + }, + { // 4 + true, + -1, // objet + 117, 117, // bateau + 58, + false, + translate ("Boat"), + 0, 0, + }, + { // 5 + true, + -1, // objet + 118, 118, // jeep + 65, + false, + translate ("Jeep"), + 0, 0, + }, + { // 6 + true, + -1, // objet + 16, 16, // armure + 106, + false, + translate ("Armour"), + 0, 0, + }, + { // 7 + true, + -1, // objet + 93, 93, // piège + 70, + false, + translate ("Sticky trap"), + 0, 0, + }, + { // 8 + true, + -1, // objet + 92, 92, // poison + 71, + false, + translate ("Poison"), + 0, 0, + }, + { // 9 + true, + -1, // objet + 85, 85, // dynamite + 57, + false, + translate ("Dynamite"), + 0, 0, + }, + { // 10 + true, + -1, // objet + 125, 125, // mine + 63, + false, + translate ("Time bomb"), + 0, 0, + }, + { // 11 + true, + -1, // objet + 60, 60, // tomate + 28, + false, + translate ("Tomatoes"), + 0, 0, + }, + { // 12 + true, + -1, // objet + 80, 80, // bouteille + 34, + false, + translate ("Medical potion"), + 0, 0, + }, + { // 13 + true, + -1, // objet + 36, 36, // planches + 22, + false, + translate ("Planks"), + 0, 0, + }, + { // 14 + true, + -1, // objet + 44, 44, // pierres + 27, + false, + translate ("Stones"), + 0, 0, + }, + { // 15 + true, + -1, // objet + 124, 124, // drapeau + 64, + true, + translate ("Flag"), + 0, 0, + }, + { // 16 + true, + -1, // objet + 123, 123, // fer + 62, + false, + translate ("Iron"), + 0, 0, + }, + { // 17 + true, + -1, // objet + 82, 82, // fleurs1 + 72, + false, + translate ("Flowers"), + 0, 0, + }, + { // 18 + true, + -1, // objet + 84, 84, // fleurs2 + 73, + false, + translate ("Flowers"), + 0, 0, + }, + { // 19 + true, + -1, // objet + 95, 95, // fleurs3 + 74, + false, + translate ("Flowers"), + 0, 0, + }, + { // 20 + true, + -1, // objet + 61, 61, // cabane + 19, + true, + translate ("Garden shed"), + 0, 0, + }, + { // 21 + true, + -1, // objet + -52, -56, // couveuse + 25, + false, + translate ("Incubator"), + 0, 0, + }, + { // 22 + true, + -1, // objet + -80, -84, // téléporteur + 101, + false, + translate ("Teleporter"), + 0, 0, + }, + { // 23 + true, + -1, // objet + 28, 29, // laboratoire + 35, + true, + translate ("Laboratory"), + 0, 0, + }, + { // 24 + true, + -1, // objet + 121, 122, // mine de fer + 61, + true, + translate ("Mine"), + 0, 0, + }, + { // 25 + true, + -1, // objet + 119, 120, // usine + 59, + true, + translate ("Workshop"), + 0, 0, + }, + { // 26 + true, + -1, // objet + 27, 27, // tour + 33, + true, + translate ("Protection tower"), + 0, 0, + }, + { // STATFEU = 27 + true, + -2, // feu + 0, 0, // + 37, + true, + translate ("Fire"), + 0, 0, + }, + { // STATROBOT = 28 + true, + 4, // robot + 0, 0, // + 56, + false, + translate ("Master robot"), + 0, 0, + }, + { // STATTRACKS = 29 + true, + 3, // tracks + 0, 0, // + 17, + false, + translate ("Bulldozer"), + 0, 0, + }, + { // STATBOMBE = 30 + true, + 5, // bombe + 0, 0, // + 38, + false, + translate ("Bouncing bomb"), + 0, 0, + }, + { // STATARAIGNEE = 31 + true, + 1, // araignée + 0, 0, // + 15, + false, + translate ("Spider"), + 0, 0, + }, + { // STATVIRUS = 32 + true, + 2, // virus + 0, 0, // + 16, + false, + translate ("Virus"), + 0, 0, + }, + { // STATELECTRO = 33 + true, + 7, // électro + 0, 0, // + 75, + false, + translate ("Electrocutor"), + 0, 0, + }, + + { + false, + -1, + 0, 0, + -1, + false, + "", + 999, 999, + }, +}; +// clang-format on + +// Retourne la statistique correspondant à un rang donné. + +Statistic * +StatisticGet (Sint32 rank) +{ + Statistic * pStatistic; + + pStatistic = table_statistic; + while (pStatistic->nb == 0) + pStatistic++; + + while (rank > 0) + { + if (pStatistic->bExist) + pStatistic++; + while (pStatistic->nb == 0) + pStatistic++; + rank--; + } + + return pStatistic; +} + +// Réinitialise les statistiques. + +void +CDecor::StatisticInit () +{ + Statistic * pStatistic; + + pStatistic = table_statistic; + while (pStatistic->bExist) + { + pStatistic->lastShow = 0; + pStatistic++; + } + + m_statNb = 0; + m_statFirst = 0; + m_bStatUp = false; + m_bStatDown = false; + m_statHili = -1; + m_bStatRecalc = true; // faudra tout recalculer +} + +// Met à jour tous les compteurs des statistiques. + +void +CDecor::StatisticUpdate () +{ + Sint32 rank, x, y, icon, nb; + bool bHach; + Statistic * pStatistic; + + m_nbStatHach = 0; + m_nbStatHachBlupi = 0; + m_nbStatHachPlanche = 0; + m_nbStatHachTomate = 0; + m_nbStatHachMetal = 0; + m_nbStatHachRobot = 0; + m_nbStatHome = 0; + m_nbStatHomeBlupi = 0; + m_nbStatRobots = 0; + + pStatistic = table_statistic; + while (pStatistic->bExist) + { + pStatistic->nb = 0; + pStatistic++; + } + + for (rank = 0; rank < MAXBLUPI; rank++) + { + if (m_blupi[rank].bExist) + { + if ( + m_blupi[rank].perso == 0 && m_blupi[rank].action != ACTION_TCHAO && + m_blupi[rank].action != ACTION_BURN) // blupi ? + { + if (m_blupi[rank].bMalade) + table_statistic[STATBLUPIm].nb++; + else + { + if (m_blupi[rank].energy <= MAXENERGY / 4) + table_statistic[STATBLUPIf].nb++; + else + table_statistic[STATBLUPI].nb++; + } + x = (m_blupi[rank].cel.x / 2) * 2; + y = (m_blupi[rank].cel.y / 2) * 2; + if ( + m_decor[x / 2][y / 2].floorChannel == CHFLOOR && + m_decor[x / 2][y / 2].floorIcon == 17) // dalle hachurée ? + m_nbStatHachBlupi++; + if ( + m_decor[x / 2][y / 2].objectChannel == CHOBJECT && + m_decor[x / 2][y / 2].objectIcon == 113) // maison ? + m_nbStatHomeBlupi++; + } + if (m_blupi[rank].perso == 8) // disciple ? + table_statistic[STATDISCIPLE].nb++; + + // Hide enemies from the stat when hidden by the fog + bool hide = false; + if (this->GetSkill () >= 1 && this->m_bFog) + { + auto fogCel = m_blupi[rank].cel; + fogCel.x = (fogCel.x / 4) * 4; + fogCel.y = (fogCel.y / 4) * 4; + if (m_decor[fogCel.x / 2][fogCel.y / 2].fog == FOGHIDE) // hidden? + hide = true; + } + + if (m_blupi[rank].perso == 4) // robot ? + { + if (!hide) + table_statistic[STATROBOT].nb++; + m_nbStatRobots++; + x = (m_blupi[rank].cel.x / 2) * 2; + y = (m_blupi[rank].cel.y / 2) * 2; + if ( + m_decor[x / 2][y / 2].floorChannel == CHFLOOR && + m_decor[x / 2][y / 2].floorIcon == 17) // dalle hachurée ? + m_nbStatHachRobot++; + } + if (m_blupi[rank].perso == 3) // tracks ? + { + if (!hide) + table_statistic[STATTRACKS].nb++; + if (!m_term.bHachRobot) // pas robot sur hachures ? + m_nbStatRobots++; + } + if (m_blupi[rank].perso == 1) // araignée ? + { + if (!hide) + table_statistic[STATARAIGNEE].nb++; + if (!m_term.bHachRobot) // pas robot sur hachures ? + m_nbStatRobots++; + } + if (m_blupi[rank].perso == 2) // virus ? + if (!hide) + table_statistic[STATVIRUS].nb++; + if (m_blupi[rank].perso == 5) // bombe ? + { + if (!hide) + table_statistic[STATBOMBE].nb++; + if (!m_term.bHachRobot) // pas robot sur hachures ? + m_nbStatRobots++; + } + if (m_blupi[rank].perso == 7) // électro ? + { + if (!hide) + table_statistic[STATELECTRO].nb++; + if (!m_term.bHachRobot) // pas robot sur hachures ? + m_nbStatRobots++; + } + } + } + + for (x = 0; x < MAXCELX; x += 2) + { + for (y = 0; y < MAXCELY; y += 2) + { + bHach = false; + if ( + m_decor[x / 2][y / 2].floorChannel == CHFLOOR && + m_decor[x / 2][y / 2].floorIcon == 17) // dalle hachurée ? + { + bHach = true; + m_nbStatHach++; + } + + if ( + m_decor[x / 2][y / 2].objectChannel == CHOBJECT && + m_decor[x / 2][y / 2].objectIcon == 113) // maison ? + m_nbStatHome++; + + if (m_decor[x / 2][y / 2].objectChannel == CHOBJECT) + { + icon = m_decor[x / 2][y / 2].objectIcon; + + pStatistic = table_statistic; + while (pStatistic->bExist) + { + if ( + pStatistic->perso == -1 && pStatistic->firstIcon > 0 && + icon >= pStatistic->firstIcon && icon <= pStatistic->lastIcon) + { + pStatistic->nb++; + break; + } + pStatistic++; + } + + if (icon == 36 && bHach) // planches ? + m_nbStatHachPlanche++; + if (icon == 60 && bHach) // tomates ? + m_nbStatHachTomate++; + if (icon == 14 && bHach) // métal ? + m_nbStatHachMetal++; + } + + if (m_decor[x / 2][y / 2].floorChannel == CHFLOOR) + { + icon = m_decor[x / 2][y / 2].floorIcon; + + if ( + (icon >= 52 && icon <= 56) || // couveuse ? + (icon >= 80 && icon <= 84)) // téléporteur ? + { + pStatistic = table_statistic; + while (pStatistic->bExist) + { + if ( + pStatistic->perso == -1 && pStatistic->firstIcon < 0 && + icon >= -(pStatistic->firstIcon) && + icon <= -(pStatistic->lastIcon)) + { + pStatistic->nb++; + break; + } + pStatistic++; + } + } + } + + if ( + m_decor[x / 2][y / 2].fire > 0 && + m_decor[x / 2][y / 2].fire < MoveMaxFire ()) + { + table_statistic[STATFEU].nb++; // un feu de plus + } + } + } + + pStatistic = table_statistic; + m_statNb = 0; + while (pStatistic->bExist) + { + if (pStatistic->nb > 0) + m_statNb++; + pStatistic++; + } + if (m_statNb <= STATNB) // tout visible en une page ? + { + m_bStatUp = false; + m_bStatDown = false; + m_statFirst = 0; + } + else + { + // nb <- nb de pages nécessaires + nb = (m_statNb + STATNB - 5) / (STATNB - 2); + + m_bStatUp = true; + m_bStatDown = true; + if (m_statFirst >= 1 + (nb - 1) * (STATNB - 2)) + { + m_statFirst = 1 + (nb - 1) * (STATNB - 2); + m_bStatDown = false; + } + if (m_statFirst == 0) + m_bStatUp = false; + } + + m_bStatRecalc = false; // c'est calculé +} + +// Retourne le nombre de blupi. + +Sint32 +CDecor::StatisticGetBlupi () +{ + return table_statistic[STATBLUPIf].nb + table_statistic[STATBLUPIm].nb + + table_statistic[STATBLUPI].nb; +} + +// Retourne le nombre de cellules en feu. + +Sint32 +CDecor::StatisticGetFire () +{ + return table_statistic[STATFEU].nb; +} + +// Dessine toutes les statistiques. + +void +CDecor::StatisticDraw () +{ + Point pos; + Rect rect; + Sint32 rank, icon, nb; + Statistic * pStatistic; + char text[50]; + const char * textRes; + + pStatistic = table_statistic; + + while (pStatistic->nb == 0) + pStatistic++; + + nb = m_statFirst; + while (nb > 0) + { + if (pStatistic->bExist) + pStatistic++; + while (pStatistic->nb == 0) + pStatistic++; + nb--; + } + + textRes = ""; + for (rank = 0; rank < STATNB; rank++) + { + pos.x = POSSTATX + DIMSTATX * (rank / (STATNB / 2)); + pos.y = POSSTATY + DIMSTATY * (rank % (STATNB / 2)); + rect.left = pos.x; + rect.right = pos.x + DIMSTATX; + rect.top = pos.y; + rect.bottom = pos.y + DIMSTATY; + + m_pPixmap->DrawPart (-1, CHBACK, pos, rect); // dessine le fond + + if (rank == 0 && m_bStatUp) + { + icon = 6 + 66; // flèche up + if (rank == m_statHili) // statistique survolée ? + icon++; + pos.x -= 3; + pos.y -= 5; + if (pStatistic->drawIcon == 68) + pos.x += 26; + m_pPixmap->DrawIcon (-1, CHBUTTON, icon, pos); // flèche up + continue; + } + + if (rank == STATNB - 1 && m_bStatDown) + { + icon = 6 + 68; // flèche down + if (rank == m_statHili) // statistique survolée ? + icon++; + pos.x += 23; + pos.y -= 5; + m_pPixmap->DrawIcon (-1, CHBUTTON, icon, pos); // flèche down + continue; + } + + if (!pStatistic->bExist) + goto next; + + icon = 6 + pStatistic->drawIcon; + + if (rank == m_statHili) // statistique survolée ? + { + m_pPixmap->DrawIconDemi (-1, CHBLUPI, ICON_HILI_STAT, pos); + textRes = gettext (pStatistic->text); + } + + if (pStatistic->nb > 0) + { + pos.x -= IsRightReading () ? -21 : 3; + pos.y -= 5; + m_pPixmap->DrawIcon (-1, CHBUTTON, icon, pos); + + nb = pStatistic->nb; + snprintf (text, sizeof (text), "%d", nb); + pos.x += IsRightReading () ? -21 + 22 : 3 + 34; + pos.y += 5 + 7; + DrawText (m_pPixmap, pos, text); + } + + next: + if (pStatistic->bExist) + pStatistic++; + while (pStatistic->nb == 0) + pStatistic++; + } + + // Dans un bouton stop/setup/write ? + if (!strlen (textRes) && m_statHili >= 100) + { + if (m_statHili == 100) + textRes = gettext ("Interrupt"); + if (m_statHili == 101) + textRes = gettext ("Settings"); + if (m_statHili == 102) + textRes = gettext ("Save"); + } + + // Dessine le nom de la statistique survolée. + pos.x = 0; + pos.y = 404; + rect.left = pos.x; + rect.right = pos.x + POSDRAWX; + rect.top = pos.y; + rect.bottom = pos.y + 16; + m_pPixmap->DrawPart (-1, CHBACK, pos, rect); // dessine le fond + + if (strlen (textRes)) + { + nb = GetTextWidth (textRes); + pos.x += (POSDRAWX_ - nb) / 2; + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawText (m_pPixmap, pos, textRes); + } +} + +// Génère les statistiques. + +void +CDecor::GenerateStatictic () +{ + if (m_bBuild) + return; + + if (m_bStatRecalc || m_phase % 20 == 10) + { + StatisticUpdate (); // met à jour les compteurs + } + + StatisticDraw (); // redessine tout +} + +// Bouton pressé dans les statistiques. + +bool +CDecor::StatisticDown (Point pos) +{ + Sint32 hili, rank, x, y, show, icon; + Point cel; + Statistic * pStatistic; + + StatisticUpdate (); + + bool disable; + hili = StatisticDetect (pos, disable); + if (hili < 0 || disable) + return false; + + if (m_bStatUp && hili == 0) // flèche up ? + { + m_statFirst -= STATNB - 2; + if (m_statFirst < STATNB - 1) + m_statFirst = 0; + StatisticUpdate (); + pos.x = LXIMAGE () / 2; + pos.y = LYIMAGE () / 2; + m_pSound->PlayImage (SOUND_OPEN, pos); + return true; + } + + if (m_bStatDown && hili == STATNB - 1) // flèche down ? + { + if (m_statFirst == 0) + m_statFirst = STATNB - 1; + else + m_statFirst += STATNB - 2; + StatisticUpdate (); + pos.x = LXIMAGE () / 2; + pos.y = LYIMAGE () / 2; + m_pSound->PlayImage (SOUND_OPEN, pos); + return true; + } + + rank = m_statFirst + hili; + if (rank > 0 && m_bStatUp) + rank--; + pStatistic = StatisticGet (rank); + if (!pStatistic->bExist) + return false; + + show = pStatistic->lastShow % pStatistic->nb; + pStatistic->lastShow++; + + if (pStatistic->perso >= 0) // blupi/araignée ? + { + for (rank = 0; rank < MAXBLUPI; rank++) + { + if (m_blupi[rank].bExist) + { + if (m_blupi[rank].perso != pStatistic->perso) + continue; + + if ( + m_blupi[rank].perso != 0 || + (m_blupi[rank].bMalade && pStatistic->drawIcon == 76) || // malade ? + (!m_blupi[rank].bMalade && m_blupi[rank].energy <= MAXENERGY / 4 && + pStatistic->drawIcon == 13) || // fatigué ? + (m_blupi[rank].energy > MAXENERGY / 4 && + pStatistic->drawIcon == 14)) // énergique ? + { + if (show == 0) + { + if ( + m_blupi[rank].perso == 0 || // blupi ? + m_blupi[rank].perso == 8) // disciple ? + { + BlupiDeselect (); + m_blupi[rank].bHili = true; + m_rankBlupiHili = rank; // sélectionne + m_nbBlupiHili = 1; + } + BlupiSetArrow (rank, true); + cel = m_blupi[rank].cel; + goto select; + } + show--; + } + } + } + } + + if ( + pStatistic->perso == -1 && // objet ? + pStatistic->firstIcon > 0) + { + for (x = 0; x < MAXCELX; x += 2) + { + for (y = 0; y < MAXCELY; y += 2) + { + if (m_decor[x / 2][y / 2].objectChannel == CHOBJECT) + { + icon = m_decor[x / 2][y / 2].objectIcon; + + if (icon >= pStatistic->firstIcon && icon <= pStatistic->lastIcon) + { + if (show == 0) + { + cel = GetCel (x, y); + if (pStatistic->bBigIcon) + { + // Flèche plus haute. + m_celArrow = GetCel (cel, -2, -2); + } + else + m_celArrow = cel; + goto select; + } + show--; + } + } + } + } + } + + if ( + pStatistic->perso == -1 && // sol ? + pStatistic->firstIcon < 0) + { + for (x = 0; x < MAXCELX; x += 2) + { + for (y = 0; y < MAXCELY; y += 2) + { + if (m_decor[x / 2][y / 2].floorChannel == CHFLOOR) + { + icon = m_decor[x / 2][y / 2].floorIcon; + + if ( + icon >= -(pStatistic->firstIcon) && icon <= -(pStatistic->lastIcon)) + { + if (show == 0) + { + cel = GetCel (x, y); + if (pStatistic->bBigIcon) + { + // Flèche plus haute. + m_celArrow = GetCel (cel, -2, -2); + } + else + m_celArrow = cel; + goto select; + } + show--; + } + } + } + } + } + + if (pStatistic->perso == -2) // feu ? + { + for (x = 0; x < MAXCELX; x += 2) + { + for (y = 0; y < MAXCELY; y += 2) + { + if ( + m_decor[x / 2][y / 2].fire > 0 && + m_decor[x / 2][y / 2].fire < MoveMaxFire ()) + { + if (show == 0) + { + cel = GetCel (x, y); + m_celArrow = cel; + goto select; + } + show--; + } + } + } + } + + return false; + +select: + SetCorner (cel, true); + NextPhase (0); // faudra refaire la carte tout de suite + return true; +} + +// Souris déplacée dans les statistiques. + +bool +CDecor::StatisticMove (Point pos, bool & disable) +{ + Sint32 rank; + + rank = StatisticDetect (pos, disable); + + if (rank != m_statHili) // autre mise en évidence ? + m_statHili = rank; + + return false; +} + +// Bouton relâché dans les statistiques. + +bool +CDecor::StatisticUp (Point pos) +{ + return false; +} + +// Détecte dans quelle statistique est la souris. + +Sint32 +CDecor::StatisticDetect (Point pos, bool & disable) +{ + Sint32 rank; + Point _pos = pos; + + disable = false; + + if (IsRightReading ()) + _pos.x = LXIMAGE () - _pos.x; + + // Dans un bouton stop/setup/write ? + if ( + _pos.x >= 10 && _pos.x <= 10 + 42 * 3 && _pos.y >= 422 && + _pos.y <= 422 + 40) + { + _pos.x -= 10; + if (_pos.x % 42 > 40) + return -1; + return 100 + _pos.x / 42; + } + + if ( + pos.x >= POSSTATX && pos.x <= POSSTATX + DIMSTATX * 2 && + pos.y >= POSSTATY && pos.y <= POSSTATY + DIMSTATY * (STATNB / 2)) + { + rank = ((pos.x - POSSTATX) / DIMSTATX) * (STATNB / 2); + rank += ((pos.y - POSSTATY) / DIMSTATY); + if (rank >= STATNB) + return -1; + + if (rank == 11 && this->m_bStatDown) + return rank; + + if (rank == 0 && this->m_bStatUp) + return rank; + + auto pStatistic = StatisticGet (m_statFirst + rank - !!m_bStatUp); + if ( + this->GetSkill () >= 1 && pStatistic->perso >= 0 && + (pStatistic->perso != 0 && pStatistic->perso != 8)) + { + disable = true; + } + + return rank; + } + + return -1; +} diff --git a/src/def.h b/src/def.h new file mode 100644 index 0000000..b37fd21 --- /dev/null +++ b/src/def.h @@ -0,0 +1,638 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include + +#include "display.h" +#include "misc.h" + +// clang-format off +#define _INTRO true // true for init screen + +#define DIMDRAWX (LXIMAGE () - (LXLOGIC () - LYLOGIC ())) +#define DIMDRAWY 450 +#define POSDRAWX_ 144 +#define POSDRAWX (IsRightReading () ? LXIMAGE () - POSDRAWX_ - DIMDRAWX : POSDRAWX_) // draw surface +#define POSDRAWY 15 + +#define DIMMAPX 128 +#define DIMMAPY 128 +#define POSMAPX (IsRightReading () ? LXIMAGE () - 8 - DIMMAPX : 8) // map surface +#define POSMAPY 15 + +#define MAXCELX 200 // max cells for a world +#define MAXCELY 200 + +#define DIMCELX 60 // cell size (decor) +#define DIMCELY 30 + +#define DIMOBJX 120 // object size +#define DIMOBJY 120 + +#define DIMBLUPIX 60 // Blupi size +#define DIMBLUPIY 60 +#define SHIFTBLUPIY 5 // shift on top + +#define DIMBUTTONX 40 // button size +#define DIMBUTTONY 40 + +#define DIMJAUGEX 124 // progress size +#define DIMJAUGEY 22 + +#define DIMSTATX 60 +#define DIMSTATY 30 +#define POSSTATX (IsRightReading () ? LXIMAGE () - 12 - DIMSTATX * 2 : 12) // statistics +#define POSSTATY 220 + +#define DIMTEXTX 16 // max char size +#define DIMTEXTY 16 + +#define DIMLITTLEX 16 // max small char size +#define DIMLITTLEY 12 + +#define CHBACK 0 +#define CHFLOOR 1 +#define CHOBJECT 2 +#define CHOBJECTo 3 +#define CHBLUPI 4 +#define CHHILI 5 +#define CHFOG 6 +#define CHMASK1 7 +#define CHLITTLE 8 +#define CHMAP 9 +#define CHBUTTON 10 +#define CHGROUND 11 +#define CHJAUGE 12 +#define CHTEXT 13 +#define CHBIGNUM 14 +#define CHMASK2 15 + +#define MAX_PRIVATE_MISSIONS 20 + +#define FOGHIDE 4 +// clang-format on + +// Directions : +enum Directions { + DIRECT_E = (0 * 16), // east + DIRECT_SE = (1 * 16), // south-east + DIRECT_S = (2 * 16), // south + DIRECT_SW = (3 * 16), // south-west + DIRECT_W = (4 * 16), // west + DIRECT_NW = (5 * 16), // north-west + DIRECT_N = (6 * 16), // north + DIRECT_NE = (7 * 16), // north-east +}; +/* NO + * O | N + * \ | / + * \ | / + * \|/ + * SO -------o------- NE + * /|\ + * / | \ + * / | \ + * S | E + * (y) SE (x) + */ + +// Actions: +enum Actions { + ACTION_STOP = 0, // stop + ACTION_STOPTIRED = 1, // stop tiredness + ACTION_WALK = 2, // walk + ACTION_WALKTIRED = 3, // walk tiredness + ACTION_BUILD = 4, // build + ACTION_PICKAXE = 5, // pickaxe + ACTION_ENERGY = 6, // prend de l'énergie + ACTION_CARRY = 8, // take with a jump the object on the head (est) + ACTION_DROP = 9, // drop the object which is on the head (est) + ACTION_SAW = 10, // saw wood + ACTION_BURN = 11, // blupi is burning ! + ACTION_TCHAO = 12, // blupi disappeard ! + ACTION_EAT = 13, // blupi eats + ACTION_BORN = 14, // born + ACTION_JUMP2 = 15, // jump over an obstacle + ACTION_JUMP3 = 16, // jump over an obstacle + ACTION_JUMP4 = 17, // jump over an obstacle + ACTION_JUMP5 = 18, // jump over an obstacle + ACTION_BRIDGE = 19, // push a bridge + ACTION_MISC1 = 20, // divers 1 (hausse les épaules) + ACTION_MISC2 = 21, // divers 2 (grat-grat) + ACTION_MISC3 = 22, // divers 3 (yoyo) + ACTION_MISC1f = 23, // divers 1 fatigué (bof-bof) + ACTION_SLIDE = 24, // slide when walking + ACTION_DRINK = 25, // blupi is drinking + ACTION_LABO = 26, // blupi travaille dans son laboratoire + ACTION_DYNAMITE = 27, // blupi fait péter la dynamite + ACTION_DELAY = 28, // blupi attend un frame + ACTION_CUEILLE1 = 29, // blupi cueille des fleurs + ACTION_CUEILLE2 = 30, // blupi cueille des fleurs + ACTION_MECHE = 31, // blupi se bouche les oreilles + ACTION_STOPb = 32, // arrêt en bateau + ACTION_MARCHEb = 33, // avance en bateau + ACTION_STOPJEEP = 34, // stop when using a jeep + ACTION_WALKJEEP = 35, // going in jeep + ACTION_ELECTRO = 36, // blupi électrocuté + ACTION_GRILL1 = 37, // blupi grills (phase 1) + ACTION_GRILL2 = 38, // blupi grills (phase 2) + ACTION_GRILL3 = 39, // blupi grills (phase 3) + ACTION_MISC4 = 40, // divers 4 (ferme les yeux) + ACTION_HAPPY = 41, // blupi is happy + ACTION_ARROSE = 42, // blupi arrose + ACTION_BECHE = 43, // blupi bèche + ACTION_CUEILLE3 = 44, // blupi cueille des fleurs + ACTION_BUILDBREF = 45, // construit + ACTION_BUILDSEC = 46, // construit + ACTION_BUILDSOURD = 47, // construit + ACTION_BUILDPIERRE = 48, // construit + ACTION_PIOCHEPIERRE = 49, // pioche + ACTION_PIOCHESOURD = 50, // pioche + ACTION_MISC5 = 51, // divers 5 (ohé) + ACTION_TELEPORTE1 = 52, // téléporte + ACTION_TELEPORTE2 = 53, // téléporte + ACTION_TELEPORTE3 = 54, // téléporte + ACTION_STOPARMOR = 55, // stop armor + ACTION_WALKARMOR = 56, // walk armor + ACTION_ARMOROPEN = 57, // open armor + ACTION_ARMORCLOSE = 58, // close armor + ACTION_JUMPJEEP = 59, // jump in the jeep + ACTION_MISC6 = 60, // divers 6 (diabolo) + ACTION_S_STOP = 100, // spider: stop + ACTION_S_WALK = 101, // spider: walk + ACTION_S_JUMP = 102, // spider: jump + ACTION_S_GRILL = 103, // spider: grill in rays + ACTION_S_POISON = 105, // spider: poisoned + ACTION_S_DEAD1 = 106, // spider: dead + ACTION_S_DEAD2 = 107, // spider: dead + ACTION_S_DEAD3 = 108, // spider: dead + ACTION_V_STOP = 200, // virus: stop + ACTION_V_WALK = 201, // virus: walk + ACTION_V_GRILL = 202, // virus: grill in rays + ACTION_T_STOP = 300, // tracks: stop + ACTION_T_WALK = 301, // tracks: walk + ACTION_T_CRUSHED = 302, // tracks: crushed an object + ACTION_R_STOP = 400, // robot: stop + ACTION_R_WALK = 401, // robot: walk + ACTION_R_APLAT = 402, // robot: applatit + ACTION_R_BUILD = 403, // robot: construit + ACTION_R_DELAY = 404, // robot: construit + ACTION_R_LOAD = 405, // robot: reload + ACTION_R_CRUSHED = 406, // robot: crushed an object + ACTION_B_STOP = 500, // bomb: stop + ACTION_B_WALK = 501, // bomb: walk + ACTION_D_DELAY = 600, // detonator: wait + ACTION_E_STOP = 700, // electro: stop + ACTION_E_WALK = 701, // electro: walk + ACTION_E_BEGIN = 702, // electro: begin + ACTION_E_RAYON = 703, // electro: rayon + ACTION_D_STOP = 800, // disciple: stop + ACTION_D_WALK = 801, // disciple: walk + ACTION_D_BUILD = 802, // disciple: build + ACTION_D_PICKAXE = 803, // disciple: pickaxe + ACTION_D_SAW = 804, // disciple: saw wood + ACTION_D_TCHAO = 805, // disciple: disappeard ! + ACTION_D_CUEILLE1 = 806, // disciple: cueille des fleurs + ACTION_D_CUEILLE2 = 807, // disciple: cueille des fleurs + ACTION_D_MECHE = 808, // disciple: se bouche les oreilles + ACTION_D_ARROSE = 809, // disciple: arrose + ACTION_D_BECHE = 810, // disciple: bèche +}; + +// Sounds: +enum Sounds { + SOUND_NONE = -1, + SOUND_CLICK = 0, + SOUND_BOING = 1, + SOUND_OK1 = 2, + SOUND_OK2 = 3, + SOUND_OK3 = 4, + SOUND_GO1 = 5, + SOUND_GO2 = 6, + SOUND_GO3 = 7, + SOUND_TERM1 = 8, + SOUND_TERM2 = 9, + SOUND_TERM3 = 10, + SOUND_COUPTERRE = 11, + SOUND_COUPTOC = 12, + SOUND_JUMP = 13, + SOUND_HOP = 14, + SOUND_SAW = 15, + SOUND_FIRE = 16, + SOUND_BURN = 17, + SOUND_TCHAO = 18, + SOUND_EAT = 19, + SOUND_BORN = 20, + SOUND_S_JUMP = 21, + SOUND_S_HIHI = 22, + SOUND_PLOUF = 23, + SOUND_GOAL = 24, + SOUND_RAYON1 = 25, + SOUND_RAYON2 = 26, + SOUND_VIRUS = 27, + SOUND_SLIDE = 28, + SOUND_DRINK = 29, + SOUND_LABO = 30, + SOUND_DYNAMITE = 31, + SOUND_DOOR = 32, + SOUND_FLOWER = 33, + SOUND_T_ENGINE = 34, + SOUND_T_ECRASE = 35, + SOUND_TRAP = 36, + SOUND_AIE = 37, + SOUND_A_POISON = 38, + SOUND_R_ENGINE = 39, + SOUND_R_APLAT = 40, + SOUND_R_ROTATE = 41, + SOUND_R_LOAD = 42, + SOUND_B_JUMP = 43, + SOUND_BOAT = 44, + SOUND_JEEP = 45, + SOUND_MINE = 46, + SOUND_USINE = 47, + SOUND_E_RAYON = 48, + SOUND_E_TOURNE = 49, + SOUND_ARROSE = 50, + SOUND_BECHE = 51, + SOUND_D_BOING = 52, + SOUND_D_OK = 53, + SOUND_D_GO = 54, + SOUND_D_TERM = 55, + SOUND_BOING1 = 56, + SOUND_BOING2 = 57, + SOUND_BOING3 = 58, + SOUND_OK4 = 59, + SOUND_OK5 = 60, + SOUND_OK6 = 61, + SOUND_OK1f = 62, + SOUND_OK2f = 63, + SOUND_OK3f = 64, + SOUND_OK1e = 65, + SOUND_OK2e = 66, + SOUND_OK3e = 67, + SOUND_GO4 = 68, + SOUND_GO5 = 69, + SOUND_GO6 = 70, + SOUND_TERM4 = 71, + SOUND_TERM5 = 72, + SOUND_TERM6 = 73, + SOUND_COUPSEC = 74, + SOUND_COUPPIERRE = 75, + SOUND_COUPSOURD = 76, + SOUND_COUPBREF = 77, + SOUND_OPEN = 78, + SOUND_CLOSE = 79, + SOUND_TELEPORTE = 80, + SOUND_ARMUREOPEN = 81, + SOUND_ARMURECLOSE = 82, + SOUND_WIN = 83, + SOUND_LOST = 84, +}; + +// Buttons (play): +enum Buttons { + BUTTON_NONE = -1, + BUTTON_GO = 0, + BUTTON_STOP = 1, + BUTTON_EAT = 2, + BUTTON_CARRY = 3, + BUTTON_DEPOSE = 4, + BUTTON_ABAT = 5, + BUTTON_ROC = 6, + BUTTON_CULTIVE = 7, + BUTTON_BUILD1 = 8, + BUTTON_BUILD2 = 9, + BUTTON_BUILD3 = 10, + BUTTON_BUILD4 = 11, + BUTTON_BUILD5 = 12, + BUTTON_BUILD6 = 13, + BUTTON_WALL = 14, + BUTTON_PALIS = 15, + BUTTON_ABATn = 16, + BUTTON_ROCn = 17, + BUTTON_BRIDGE = 18, + BUTTON_TOWER = 19, + BUTTON_BOIT = 20, + BUTTON_LABO = 21, + BUTTON_FLOWER = 22, + BUTTON_FLOWERn = 23, + BUTTON_DYNAMITE = 24, + BUTTON_BOAT = 25, + BUTTON_DJEEP = 26, + BUTTON_FLAG = 27, + BUTTON_EXTRAIT = 28, + BUTTON_FABJEEP = 29, + BUTTON_FABMINE = 30, + BUTTON_FABDISC = 31, + BUTTON_REPEAT = 32, + BUTTON_DARMOR = 33, + BUTTON_MAKEARMOR = 34, + MAXBUTTON = 40, +}; + +// Errors: +enum Errors { + NONE = 0, + MISC = 1, + GROUND = 2, + FREE = 3, + PONTOP = 4, + PONTTERM = 5, + TOURISOL = 6, + TOUREAU = 7, + TELE2 = 8, + ENERGY = 9, + REPEAT = 500, +}; + +// Lutins pour la souris + +enum MouseSprites { + SPRITE_BEGIN = 1, + SPRITE_ARROW = 1, + SPRITE_POINTER = 2, + SPRITE_MAP = 3, + SPRITE_ARROWU = 4, + SPRITE_ARROWD = 5, + SPRITE_ARROWL = 6, + SPRITE_ARROWR = 7, + SPRITE_ARROWUL = 8, + SPRITE_ARROWUR = 9, + SPRITE_ARROWDL = 10, + SPRITE_ARROWDR = 11, + SPRITE_WAIT = 12, + SPRITE_EMPTY = 13, + SPRITE_FILL = 14, + SPRITE_END = 14, +}; + +enum ShiftDirection { + DIRECTION_UP = (1 << 0), + DIRECTION_DOWN = (1 << 1), + DIRECTION_LEFT = (1 << 2), + DIRECTION_RIGHT = (1 << 3), +}; + +// clang-format off +#define EV_OFFSET 0x0400 + +#define EV_UPDATE (EV_OFFSET+1) +#define EV_WARPMOUSE (EV_OFFSET+2) +#define EV_CHECKUPDATE (EV_OFFSET+3) + +#define EV_DECOR1 (EV_OFFSET+20) +#define EV_DECOR2 (EV_OFFSET+21) +#define EV_DECOR3 (EV_OFFSET+22) +#define EV_DECOR4 (EV_OFFSET+23) +#define EV_DECOR5 (EV_OFFSET+24) + +#define EV_ACTION_GO (EV_OFFSET+30) +#define EV_ACTION_ABAT1 (EV_OFFSET+31) +#define EV_ACTION_ABAT2 (EV_OFFSET+32) +#define EV_ACTION_ABAT3 (EV_OFFSET+33) +#define EV_ACTION_ABAT4 (EV_OFFSET+34) +#define EV_ACTION_ABAT5 (EV_OFFSET+35) +#define EV_ACTION_ABAT6 (EV_OFFSET+36) +#define EV_ACTION_BUILD1 (EV_OFFSET+37) +#define EV_ACTION_BUILD2 (EV_OFFSET+38) +#define EV_ACTION_BUILD3 (EV_OFFSET+39) +#define EV_ACTION_BUILD4 (EV_OFFSET+40) +#define EV_ACTION_BUILD5 (EV_OFFSET+41) +#define EV_ACTION_BUILD6 (EV_OFFSET+42) +#define EV_ACTION_STOP (EV_OFFSET+43) +#define EV_ACTION_CARRY (EV_OFFSET+44) +#define EV_ACTION_DROP (EV_OFFSET+45) +#define EV_ACTION_ROC1 (EV_OFFSET+46) +#define EV_ACTION_ROC2 (EV_OFFSET+47) +#define EV_ACTION_ROC3 (EV_OFFSET+48) +#define EV_ACTION_ROC4 (EV_OFFSET+49) +#define EV_ACTION_ROC5 (EV_OFFSET+50) +#define EV_ACTION_ROC6 (EV_OFFSET+51) +#define EV_ACTION_ROC7 (EV_OFFSET+52) +#define EV_ACTION_WALL (EV_OFFSET+53) +#define EV_ACTION_CULTIVE (EV_OFFSET+54) +#define EV_ACTION_CULTIVE2 (EV_OFFSET+55) +#define EV_ACTION_EAT (EV_OFFSET+56) +#define EV_ACTION_MAKE (EV_OFFSET+57) +#define EV_ACTION_BUILD (EV_OFFSET+58) +#define EV_ACTION_PALIS (EV_OFFSET+59) +#define EV_ACTION_NEWBLUPI (EV_OFFSET+60) +#define EV_ACTION_BRIDGEE (EV_OFFSET+61) +#define EV_ACTION_BRIDGES (EV_OFFSET+62) +#define EV_ACTION_BRIDGEO (EV_OFFSET+63) +#define EV_ACTION_BRIDGEN (EV_OFFSET+64) +#define EV_ACTION_BRIDGEEL (EV_OFFSET+65) +#define EV_ACTION_BRIDGESL (EV_OFFSET+66) +#define EV_ACTION_BRIDGEOL (EV_OFFSET+67) +#define EV_ACTION_BRIDGENL (EV_OFFSET+68) +#define EV_ACTION_TOWER (EV_OFFSET+69) +#define EV_ACTION_CARRY2 (EV_OFFSET+70) +#define EV_ACTION_DROP2 (EV_OFFSET+71) +#define EV_ACTION_EAT2 (EV_OFFSET+72) +#define EV_ACTION_DRINK (EV_OFFSET+73) +#define EV_ACTION_DRINK2 (EV_OFFSET+74) +#define EV_ACTION_LABO (EV_OFFSET+75) +#define EV_ACTION_FLOWER1 (EV_OFFSET+76) +#define EV_ACTION_FLOWER2 (EV_OFFSET+77) +#define EV_ACTION_DYNAMITE (EV_OFFSET+78) +#define EV_ACTION_DYNAMITE2 (EV_OFFSET+79) +#define EV_ACTION_T_DYNAMITE (EV_OFFSET+80) +#define EV_ACTION_FLOWER3 (EV_OFFSET+81) +#define EV_ACTION_R_BUILD1 (EV_OFFSET+82) +#define EV_ACTION_R_BUILD2 (EV_OFFSET+83) +#define EV_ACTION_R_BUILD3 (EV_OFFSET+84) +#define EV_ACTION_R_BUILD4 (EV_OFFSET+85) +#define EV_ACTION_R_MAKE1 (EV_OFFSET+86) +#define EV_ACTION_R_MAKE2 (EV_OFFSET+87) +#define EV_ACTION_R_MAKE3 (EV_OFFSET+88) +#define EV_ACTION_R_MAKE4 (EV_OFFSET+89) +#define EV_ACTION_R_BUILD5 (EV_OFFSET+90) +#define EV_ACTION_R_MAKE5 (EV_OFFSET+91) +#define EV_ACTION_BOATE (EV_OFFSET+92) +#define EV_ACTION_BOATS (EV_OFFSET+93) +#define EV_ACTION_BOATO (EV_OFFSET+94) +#define EV_ACTION_BOATN (EV_OFFSET+95) +#define EV_ACTION_BOATDE (EV_OFFSET+96) +#define EV_ACTION_BOATDS (EV_OFFSET+97) +#define EV_ACTION_BOATDO (EV_OFFSET+98) +#define EV_ACTION_BOATDN (EV_OFFSET+99) +#define EV_ACTION_BOATAE (EV_OFFSET+100) +#define EV_ACTION_BOATAS (EV_OFFSET+101) +#define EV_ACTION_BOATAO (EV_OFFSET+102) +#define EV_ACTION_BOATAN (EV_OFFSET+103) +#define EV_ACTION_MJEEP (EV_OFFSET+104) +#define EV_ACTION_DJEEP (EV_OFFSET+105) +#define EV_ACTION_FLAG (EV_OFFSET+106) +#define EV_ACTION_FLAG2 (EV_OFFSET+107) +#define EV_ACTION_FLAG3 (EV_OFFSET+108) +#define EV_ACTION_EXTRAIT (EV_OFFSET+109) +#define EV_ACTION_FABJEEP (EV_OFFSET+110) +#define EV_ACTION_FABMINE (EV_OFFSET+111) +#define EV_ACTION_MINE (EV_OFFSET+112) +#define EV_ACTION_MINE2 (EV_OFFSET+113) +#define EV_ACTION_R_BUILD6 (EV_OFFSET+114) +#define EV_ACTION_R_MAKE6 (EV_OFFSET+115) +#define EV_ACTION_E_RAYON (EV_OFFSET+116) +#define EV_ACTION_ELECTRO (EV_OFFSET+117) +#define EV_ACTION_ELECTROm (EV_OFFSET+118) +#define EV_ACTION_GRILLE (EV_OFFSET+119) +#define EV_ACTION_HOUSE (EV_OFFSET+120) +#define EV_ACTION_FABDISC (EV_OFFSET+121) +#define EV_ACTION_A_MORT (EV_OFFSET+122) +#define EV_ACTION_REPEAT (EV_OFFSET+123) +#define EV_ACTION_TELEPORTE00 (EV_OFFSET+124) +#define EV_ACTION_TELEPORTE10 (EV_OFFSET+125) +#define EV_ACTION_TELEPORTE01 (EV_OFFSET+126) +#define EV_ACTION_TELEPORTE11 (EV_OFFSET+127) +#define EV_ACTION_FABARMURE (EV_OFFSET+128) +#define EV_ACTION_MARMURE (EV_OFFSET+129) +#define EV_ACTION_DARMURE (EV_OFFSET+130) + +#define EV_BUTTON0 (EV_OFFSET+200) +#define EV_BUTTON1 (EV_OFFSET+201) +#define EV_BUTTON2 (EV_OFFSET+202) +#define EV_BUTTON3 (EV_OFFSET+203) +#define EV_BUTTON4 (EV_OFFSET+204) +#define EV_BUTTON5 (EV_OFFSET+205) +#define EV_BUTTON6 (EV_OFFSET+206) +#define EV_BUTTON7 (EV_OFFSET+207) +#define EV_BUTTON8 (EV_OFFSET+208) +#define EV_BUTTON9 (EV_OFFSET+209) +#define EV_BUTTON10 (EV_OFFSET+210) +#define EV_BUTTON11 (EV_OFFSET+211) +#define EV_BUTTON12 (EV_OFFSET+212) +#define EV_BUTTON13 (EV_OFFSET+213) +#define EV_BUTTON14 (EV_OFFSET+214) +#define EV_BUTTON15 (EV_OFFSET+215) +#define EV_BUTTON16 (EV_OFFSET+216) +#define EV_BUTTON17 (EV_OFFSET+217) +#define EV_BUTTON18 (EV_OFFSET+218) +#define EV_BUTTON19 (EV_OFFSET+219) +#define EV_BUTTON20 (EV_OFFSET+220) +#define EV_BUTTON21 (EV_OFFSET+221) +#define EV_BUTTON22 (EV_OFFSET+222) +#define EV_BUTTON23 (EV_OFFSET+223) +#define EV_BUTTON24 (EV_OFFSET+224) +#define EV_BUTTON25 (EV_OFFSET+225) +#define EV_BUTTON26 (EV_OFFSET+226) +#define EV_BUTTON27 (EV_OFFSET+227) +#define EV_BUTTON28 (EV_OFFSET+228) +#define EV_BUTTON29 (EV_OFFSET+229) +#define EV_BUTTON30 (EV_OFFSET+230) +#define EV_BUTTON31 (EV_OFFSET+231) +#define EV_BUTTON32 (EV_OFFSET+232) +#define EV_BUTTON33 (EV_OFFSET+233) +#define EV_BUTTON34 (EV_OFFSET+234) +#define EV_BUTTON35 (EV_OFFSET+235) +#define EV_BUTTON36 (EV_OFFSET+236) +#define EV_BUTTON37 (EV_OFFSET+237) +#define EV_BUTTON38 (EV_OFFSET+238) +#define EV_BUTTON39 (EV_OFFSET+239) + +#define EV_READ0 (EV_OFFSET+300) +#define EV_READ1 (EV_OFFSET+301) +#define EV_READ2 (EV_OFFSET+302) +#define EV_READ3 (EV_OFFSET+303) +#define EV_READ4 (EV_OFFSET+304) +#define EV_READ5 (EV_OFFSET+305) +#define EV_READ6 (EV_OFFSET+306) +#define EV_READ7 (EV_OFFSET+307) +#define EV_READ8 (EV_OFFSET+308) +#define EV_READ9 (EV_OFFSET+309) + +#define EV_READ_EXIT (EV_OFFSET+320) + +#define EV_WRITE0 (EV_OFFSET+310) +#define EV_WRITE1 (EV_OFFSET+311) +#define EV_WRITE2 (EV_OFFSET+312) +#define EV_WRITE3 (EV_OFFSET+313) +#define EV_WRITE4 (EV_OFFSET+314) +#define EV_WRITE5 (EV_OFFSET+315) +#define EV_WRITE6 (EV_OFFSET+316) +#define EV_WRITE7 (EV_OFFSET+317) +#define EV_WRITE8 (EV_OFFSET+318) +#define EV_WRITE9 (EV_OFFSET+319) + +#define EV_PHASE_INIT (EV_OFFSET+500) +#define EV_PHASE_PLAY (EV_OFFSET+501) +#define EV_PHASE_BUILD (EV_OFFSET+502) +#define EV_PHASE_READ (EV_OFFSET+503) +#define EV_PHASE_WRITE (EV_OFFSET+504) +#define EV_PHASE_INFO (EV_OFFSET+505) +#define EV_PHASE_BUTTON (EV_OFFSET+506) +#define EV_PHASE_TERM (EV_OFFSET+507) +#define EV_PHASE_WIN (EV_OFFSET+508) +#define EV_PHASE_LOST (EV_OFFSET+509) +#define EV_PHASE_STOP (EV_OFFSET+510) +#define EV_PHASE_SETUP (EV_OFFSET+511) +#define EV_PHASE_MUSIC (EV_OFFSET+512) +#define EV_PHASE_PLAYMOVIE (EV_OFFSET+513) +#define EV_PHASE_WINMOVIE (EV_OFFSET+514) +#define EV_PHASE_SCHOOL (EV_OFFSET+515) +#define EV_PHASE_MISSION (EV_OFFSET+516) +#define EV_PHASE_LASTWIN (EV_OFFSET+517) +#define EV_PHASE_WRITEp (EV_OFFSET+518) +#define EV_PHASE_SETUPp (EV_OFFSET+519) +#define EV_PHASE_REGION (EV_OFFSET+520) +#define EV_PHASE_INSERT (EV_OFFSET+521) +#define EV_PHASE_HISTORY0 (EV_OFFSET+522) +#define EV_PHASE_HISTORY1 (EV_OFFSET+523) +#define EV_PHASE_HELP (EV_OFFSET+524) +#define EV_PHASE_H0MOVIE (EV_OFFSET+525) +#define EV_PHASE_H1MOVIE (EV_OFFSET+526) +#define EV_PHASE_H2MOVIE (EV_OFFSET+527) +#define EV_PHASE_TESTCD (EV_OFFSET+528) +#define EV_PHASE_MANUEL (EV_OFFSET+529) +#define EV_PHASE_PRIVATE (EV_OFFSET+530) +#define EV_PHASE_UNDO (EV_OFFSET+531) +#define EV_PHASE_BYE (EV_OFFSET+532) +#define EV_PHASE_SKILL1 (EV_OFFSET+533) +#define EV_PHASE_SKILL2 (EV_OFFSET+534) +#define EV_PHASE_DEMO (EV_OFFSET+535) +#define EV_PHASE_INTRO1 (EV_OFFSET+536) +#define EV_PHASE_SETTINGS (EV_OFFSET+537) + +#define EV_MUSIC_STOP (EV_OFFSET+550) + +#define EV_SETUP_EXIT (EV_OFFSET+560) + +#define EV_PREV (EV_OFFSET+600) +#define EV_NEXT (EV_OFFSET+601) +#define EV_MOVIE (EV_OFFSET+602) +#define EV_MOVIE_PLAY (EV_OFFSET+603) +// clang-format on + +// Conditions pour gagner. + +typedef struct { + Sint16 bHachBlupi; // blupi sur dalle hachurée + Sint16 bHachPlanche; // planches sur dalle hachurée + Sint16 bStopFire; // feu éteint + Sint16 nbMinBlupi; // nb de blupi nécessaires + Sint16 nbMaxBlupi; // nb de blupi nécessaires + Sint16 bHomeBlupi; // blupi à la maison + Sint16 bKillRobots; // plus d'ennemis + Sint16 bHachTomate; // tomates sur dalle hachurée + Sint16 bHachMetal; // métal sur dalle hachurée + Sint16 bHachRobot; // robot sur dalle hachurée + Sint16 reserve[14]; +} Term; diff --git a/src/display.cxx b/src/display.cxx new file mode 100644 index 0000000..98c8040 --- /dev/null +++ b/src/display.cxx @@ -0,0 +1,97 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include + +#include "blupi.h" +#include "display.h" + +Display::Display () +{ + this->width = this->getLogicWidth (); + this->height = this->getLogicHeight (); +} + +Display & +Display::getDisplay () +{ + static Display display; + return display; +} + +bool +Display::isWide () +{ + return this->getWidth () > this->getLogicWidth (); +} + +void +Display::readDisplaySize () +{ + SDL_DisplayMode displayMode; + int res; + + if (g_window) + res = SDL_GetWindowDisplayMode (g_window, &displayMode); + else + res = SDL_GetCurrentDisplayMode (0, &displayMode); + + if (res < 0) + return; + + this->setDisplaySize (displayMode.w, displayMode.h); +} + +void +Display::setDisplaySize (Sint32 w, Sint32 h) +{ + this->width = w; + this->height = h; + + if (this->width < this->getLogicWidth ()) + this->width = this->getLogicWidth (); + if (this->height < this->getLogicHeight ()) + this->height = this->getLogicHeight (); +} + +Sint32 +Display::getWidth () +{ + return ( + this->getLogicHeight () * this->width / this->height + + (this->getLogicHeight () * this->width / this->height) % 2); +} + +Sint32 +Display::getHeight () +{ + return this->getLogicHeight (); +} + +Sint32 +Display::getLogicWidth () +{ + return 640; +} + +Sint32 +Display::getLogicHeight () +{ + return 480; +} diff --git a/src/display.h b/src/display.h new file mode 100644 index 0000000..4983cca --- /dev/null +++ b/src/display.h @@ -0,0 +1,73 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include + +class Display +{ +private: + Sint32 width; + Sint32 height; + +private: + Display (); + +public: + static Display & getDisplay (); + + bool isWide (); + void readDisplaySize (); + void setDisplaySize (Sint32 w, Sint32 h); + Sint32 getWidth (); + Sint32 getHeight (); + Sint32 getLogicWidth (); + Sint32 getLogicHeight (); +}; + +inline Sint32 +LXLOGIC () +{ + return Display::getDisplay ().getLogicWidth (); +} + +inline Sint32 +LYLOGIC () +{ + return Display::getDisplay ().getLogicHeight (); +} + +inline Sint32 +LXIMAGE () +{ + return Display::getDisplay ().getWidth (); +} + +inline Sint32 +LYIMAGE () +{ + return Display::getDisplay ().getHeight (); +} + +inline Sint32 +LXOFFSET () +{ + return ((LXIMAGE () - LXLOGIC ()) / 2); +} diff --git a/src/event.cxx b/src/event.cxx new file mode 100644 index 0000000..1fc70d4 --- /dev/null +++ b/src/event.cxx @@ -0,0 +1,6422 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2019, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include +#include +#include +#include +#include +#include + +#include "action.h" +#include "blupi.h" +#include "button.h" +#include "config.h" +#include "decor.h" +#include "def.h" +#include "event.h" +#include "gettext.h" +#include "menu.h" +#include "misc.h" +#include "movie.h" +#include "pixmap.h" +#include "platform.h" +#include "progress.h" +#include "sound.h" +#include "text.h" + +#ifdef _WIN32 +#define unlink _unlink +#define putenv _putenv +#else // _WIN32 +#include +#endif // !_WINE32 + +#define DEF_TIME_HELP 10000 // ~10 minutes +#define DEF_TIME_DEMO 1000 // ~1 minute +#define MAXDEMO 2000 + +typedef struct { + // v1.0 + Sint16 majRev; + Sint16 minRev; + Sint16 reserve1[9]; + Sint16 exercice; // exercice en cours (0..n) + Sint16 mission; // mission en cours (0..n) + Sint16 speed; + Sint16 bMovie; + Sint16 maxMission; // dernière mission effectuée (0..n) + Sint16 scrollSpeed; + Sint16 audioVolume; + Sint16 midiVolume; + Sint16 bAccessBuild; + Sint16 prive; + Sint16 skill; + // v1.1 + Sint16 language; + // v1.2 + Sint16 musicMidi; + Sint16 fullScreen; + Sint16 zoom; + // v1.3 + Sint16 renderQuality; + + Sint16 reserve2[88]; +} DescInfo; + +// Toutes les premières lettres doivent +// être différentes ! + +static char cheat_code[9][20] = { + "vision", // 0 + "power", // 1 + "lonesome", // 2 + "allmissions", // 3 + "quick", // 4 + "helpme", // 5 + "invincible", // 6 + "superblupi", // 7 + "construire", // 8 (CPOTUSVJSF) +}; + +///////////////////////////////////////////////////////////////////////////// + +// clang-format off +static Phase table[] = +{ + { + EV_PHASE_TESTCD, + "init.png", + "back-stars.png", + CPixmap::Mode::FIX, + false, + { + { + 0 + }, + }, + }, + + { + EV_PHASE_INTRO1, + "intro1.png", + "", + CPixmap::Mode::FIX, + false, + { + { + 0 + }, + }, + }, + + { + EV_PHASE_INIT, + "init.png", + "back-stars.png", + CPixmap::Mode::FIX, + false, + { + { + EV_PHASE_DEMO, + 0, {1, 108}, + 16, 424 - 60 - 42 * 4 - 18, + { translate ("Demo") }, + }, + { + EV_PHASE_SCHOOL, + 0, {1, 79}, + 16, 424 - 60 - 42 * 3, + { translate ("Training") }, + }, + { + EV_PHASE_MISSION, + 0, {1, 80}, + 16, 424 - 60 - 42 * 2, + { translate ("Missions") }, + }, + { + EV_PHASE_PRIVATE, + 0, {1, 49}, + 16, 424 - 60 - 42 * 1, + { translate ("Construction") }, + }, + { + EV_PHASE_SETTINGS, + 0, {1, 47}, + 16, 424 - 60 - 42 * 0, + { translate ("Global settings") } + }, + { + EV_PHASE_BYE, + 0, {1, 36}, + 16, 424, + { translate ("Quit Planet Blupi") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_HISTORY0, + "history0.png", + "back-book.png", + CPixmap::Mode::FIX_REVERSABLE, + true, + { + { + EV_PHASE_INIT, + 0, {1, 50}, + 42 + 42 * 0, 433, + { translate ("Previous page") }, + }, + { + EV_PHASE_H1MOVIE, + 0, {1, 51}, + 558 - 42 * 0, 433, + { translate ("Next page") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_HISTORY1, + "history1.png", + "back-book.png", + CPixmap::Mode::FIX_REVERSABLE, + true, + { + { + EV_PHASE_HISTORY0, + 0, {1, 50}, + 42 + 42 * 0, 433, + { translate ("Previous page") }, + }, + { + EV_PHASE_H2MOVIE, + 0, {1, 51}, + 558 - 42 * 0, 433, + { translate ("Next page") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_INFO, + "info%.3d.png", + "back-book.png", + CPixmap::Mode::FIX_REVERSABLE, + false, + { + { + EV_PREV, + 0, {1, 50}, + 558 - 42 * 2, 433, + { translate ("Previous game") }, + }, + { + EV_PHASE_PLAYMOVIE, + 0, {1, 48}, + 558 - 42 * 1, 433, + { translate ("Play this game") }, + }, + { + EV_NEXT, + 0, {1, 51}, + 558 - 42 * 0, 433, + { translate ("Next game") }, + }, + { + EV_PHASE_READ, + 0, {1, 52}, + 42 + 42 * 4, 433, + { translate ("Open another game") }, + }, + { + EV_PHASE_SETUP, + 0, {1, 47}, + 42 + 42 * 7, 433, + { translate ("Settings") }, + }, + { + EV_PHASE_BUILD, + 0, {1, 49}, + 42 + 42 * 8, 433, + { translate ("Construct this game") }, + }, + { + EV_PHASE_SKILL1, + 0, {1, 94}, + 150, 230, + { translate ("Skill level") }, + }, + { + EV_PHASE_SKILL2, + 0, {1, 95}, + 150, 230 + 42, + { translate ("Skill level") }, + }, + { + EV_PHASE_INIT, + 0, {1, 40}, + 42 + 42 * 0, 433, + { translate ("Finish") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_PLAY, + "play.png", + "", + CPixmap::Mode::EXPAND_REVERSABLE, + false, + { + { + EV_PHASE_STOP, + 0, {1, 40}, + 10 + 42 * 0, 422, + {}, + }, + { + EV_PHASE_SETUPp, + 0, {1, 47}, + 10 + 42 * 1, 422, + {}, + }, + { + EV_PHASE_WRITEp, + 0, {1, 53}, + 10 + 42 * 2, 422, + {}, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_STOP, + "stop%.3d.png", + "back-book.png", + CPixmap::Mode::FIX_REVERSABLE, + false, + { + { + EV_PHASE_PLAY, + 0, {1, 77}, + 558 - 42 * 1, 433, + { translate ("Continue this game") }, + }, + { + EV_PHASE_READ, + 0, {1, 52}, + 42 + 42 * 4, 433, + { translate ("Open another game") }, + }, + { + EV_PHASE_WRITE, + 0, {1, 53}, + 42 + 42 * 5, 433, + { translate ("Save this game") }, + }, + { + EV_PHASE_SETUP, + 0, {1, 47}, + 42 + 42 * 7, 433, + { translate ("Settings") }, + }, + { + EV_PHASE_INFO, + 0, {1, 78}, + 42 + 42 * 0, 433, + { translate ("Quit this game") }, + }, + { + EV_PHASE_HELP, + 0, {1, 86}, + 42 + 42 * 9, 433, + { translate ("Help") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_HELP, + "help.png", + "back-book.png", + CPixmap::Mode::FIX_REVERSABLE, + true, + { + { + EV_PHASE_PLAY, + 0, {1, 77}, + 558 - 42 * 1, 433, + { translate ("Continue this game") }, + }, + { + EV_PHASE_READ, + 0, {1, 52}, + 42 + 42 * 4, 433, + { translate ("Open another game") }, + }, + { + EV_PHASE_WRITE, + 0, {1, 53}, + 42 + 42 * 5, 433, + { translate ("Save this game") }, + }, + { + EV_PHASE_SETUP, + 0, {1, 47}, + 42 + 42 * 7, 433, + { translate ("Settings") }, + }, + { + EV_PHASE_STOP, + 0, {1, 50}, + 42 + 42 * 0, 433, + { translate ("Previous page") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_SETUP, + "setup01.png", + "back-setup.png", + CPixmap::Mode::FIX, + false, + { + { + EV_BUTTON1, + 0, {1, 50}, + 54, 330, + { translate ("Slower") }, + }, + { + EV_BUTTON2, + 0, {1, 51}, + 54 + 40, 330, + { translate ("Faster") }, + }, + { + EV_BUTTON3, + 0, {1, 50}, + 284, 330, + { translate ("Reduce volume") }, + }, + { + EV_BUTTON4, + 0, {1, 51}, + 284 + 40, 330, + { translate ("Increase volume") }, + }, + { + EV_BUTTON5, + 0, {1, 50}, + 399, 330, + { translate ("Reduce volume") }, + }, + { + EV_BUTTON6, + 0, {1, 51}, + 399 + 40, 330, + { translate ("Increase volume") }, + }, + { + EV_BUTTON7, + 0, {1, 50}, + 514, 330, + { translate ("No video") }, + }, + { + EV_BUTTON8, + 0, {1, 51}, + 514 + 40, 330, + { translate ("Show videos") }, + }, + { + EV_BUTTON9, + 0, {1, 50}, + 169, 330, + { translate ("Slower") }, + }, + { + EV_BUTTON10, + 0, {1, 51}, + 169 + 40, 330, + { translate ("Faster") }, + }, + { + EV_SETUP_EXIT, + 0, {1, 40}, + 11, 424, + { translate ("Finish") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_SETUPp, + "setup01.png", + "back-setup.png", + CPixmap::Mode::FIX, + false, + { + { + EV_BUTTON1, + 0, {1, 50}, + 54, 330, + { translate ("Slower") }, + }, + { + EV_BUTTON2, + 0, {1, 51}, + 54 + 40, 330, + { translate ("Faster") }, + }, + { + EV_BUTTON3, + 0, {1, 50}, + 284, 330, + { translate ("Reduce volume") }, + }, + { + EV_BUTTON4, + 0, {1, 51}, + 284 + 40, 330, + { translate ("Increase volume") }, + }, + { + EV_BUTTON5, + 0, {1, 50}, + 399, 330, + { translate ("Reduce volume") }, + }, + { + EV_BUTTON6, + 0, {1, 51}, + 399 + 40, 330, + { translate ("Increase volume") }, + }, + { + EV_BUTTON7, + 0, {1, 50}, + 514, 330, + { translate ("No video") }, + }, + { + EV_BUTTON8, + 0, {1, 51}, + 514 + 40, 330, + { translate ("Show videos") }, + }, + { + EV_BUTTON9, + 0, {1, 50}, + 169, 330, + { translate ("Slower") }, + }, + { + EV_BUTTON10, + 0, {1, 51}, + 169 + 40, 330, + { translate ("Faster") }, + }, + { + EV_PHASE_PLAY, + 0, {1, 77}, + 11, 424, + { translate ("Continue this game") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_READ, + "read.png", + "back-chest-r.png", + CPixmap::Mode::FIX_REVERSABLE, + false, + { + { + EV_READ0, + 0, {0}, + 420, 30 + 42 * 0, + {}, + }, + { + EV_READ1, + 0, {0}, + 420, 30 + 42 * 1, + {}, + }, + { + EV_READ2, + 0, {0}, + 420, 30 + 42 * 2, + {}, + }, + { + EV_READ3, + 0, {0}, + 420, 30 + 42 * 3, + {}, + }, + { + EV_READ4, + 0, {0}, + 420, 30 + 42 * 4, + {}, + }, + { + EV_READ5, + 0, {0}, + 420, 30 + 42 * 5, + {}, + }, + { + EV_READ6, + 0, {0}, + 420, 30 + 42 * 6, + {}, + }, + { + EV_READ7, + 0, {0}, + 420, 30 + 42 * 7, + {}, + }, + { + EV_READ8, + 0, {0}, + 420, 30 + 42 * 8, + {}, + }, + { + EV_READ9, + 0, {0}, + 420, 30 + 42 * 9, + {}, + }, + { + EV_READ_EXIT, + 0, {1, 40}, + 16, 424, + { translate ("Finish") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_WRITE, + "write.png", + "back-chest-w.png", + CPixmap::Mode::FIX_REVERSABLE, + false, + { + { + EV_WRITE0, + 0, {0}, + 420, 30 + 42 * 0, + {}, + }, + { + EV_WRITE1, + 0, {0}, + 420, 30 + 42 * 1, + {}, + }, + { + EV_WRITE2, + 0, {0}, + 420, 30 + 42 * 2, + {}, + }, + { + EV_WRITE3, + 0, {0}, + 420, 30 + 42 * 3, + {}, + }, + { + EV_WRITE4, + 0, {0}, + 420, 30 + 42 * 4, + {}, + }, + { + EV_WRITE5, + 0, {0}, + 420, 30 + 42 * 5, + {}, + }, + { + EV_WRITE6, + 0, {0}, + 420, 30 + 42 * 6, + {}, + }, + { + EV_WRITE7, + 0, {0}, + 420, 30 + 42 * 7, + {}, + }, + { + EV_WRITE8, + 0, {0}, + 420, 30 + 42 * 8, + {}, + }, + { + EV_WRITE9, + 0, {0}, + 420, 30 + 42 * 9, + {}, + }, + { + EV_PHASE_STOP, + 0, {1, 40}, + 16, 424, + { translate ("Finish") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_WRITEp, + "write.png", + "back-chest-w.png", + CPixmap::Mode::FIX_REVERSABLE, + false, + { + { + EV_WRITE0, + 0, {0}, + 420, 30 + 42 * 0, + {}, + }, + { + EV_WRITE1, + 0, {0}, + 420, 30 + 42 * 1, + {}, + }, + { + EV_WRITE2, + 0, {0}, + 420, 30 + 42 * 2, + {}, + }, + { + EV_WRITE3, + 0, {0}, + 420, 30 + 42 * 3, + {}, + }, + { + EV_WRITE4, + 0, {0}, + 420, 30 + 42 * 4, + {}, + }, + { + EV_WRITE5, + 0, {0}, + 420, 30 + 42 * 5, + {}, + }, + { + EV_WRITE6, + 0, {0}, + 420, 30 + 42 * 6, + {}, + }, + { + EV_WRITE7, + 0, {0}, + 420, 30 + 42 * 7, + {}, + }, + { + EV_WRITE8, + 0, {0}, + 420, 30 + 42 * 8, + {}, + }, + { + EV_WRITE9, + 0, {0}, + 420, 30 + 42 * 9, + {}, + }, + { + EV_PHASE_PLAY, + 0, {1, 77}, + 16, 424, + { translate ("Continue this game") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_LOST, + "lost.png", + "back-lost.png", + CPixmap::Mode::FIX, + true, + { + { + EV_PHASE_INFO, + 0, {1, 50}, + 9, 431, + { translate ("Restart this game") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_WIN, + "win.png", + "back-win.png", + CPixmap::Mode::FIX, + true, + { + { + EV_NEXT, + 0, {1, 51}, + 9, 431, + { translate ("Next game") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_LASTWIN, + "last%.3d.png", + "", + CPixmap::Mode::FIX, + true, + { + { + EV_PHASE_INIT, + 0, {1, 51}, + 9, 431, + { translate ("Next game") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_BUILD, + "build.png", + "", + CPixmap::Mode::EXPAND_REVERSABLE, + true, + { + { + EV_DECOR1, // pose des sols + 0, {6, 0, 1, 2, 3, 4, 25}, + 11 + 42 * 2, 190 + 42 * 0, + { + translate ("Normal ground"), + translate ("Inflammable ground"), + translate ("Sterile ground"), + translate ("Water"), + translate ("Special pavings"), + translate ("Incubator or teleporter") + }, + }, + { + EV_DECOR2, // pose des plantes + 0, {4, 6, 7, 8, 11}, + 11 + 42 * 2, 190 + 42 * 1, + { + translate ("Delete item"), + translate ("Decorative plants"), + translate ("Tree"), + translate ("Flowers") + }, + }, + { + EV_DECOR3, // pose des batiments + 0, {11, 18, 81, 33, 61, 82, 93, 20, 21, 22, 57, 58}, + 11 + 42 * 2, 190 + 42 * 2, + { + translate ("Delete item"), + translate ("Buildings"), + translate ("Protection tower"), + translate ("Mine"), + translate ("Enemy buildings"), + translate ("Enemy barrier"), + translate ("Wall or palisade"), + translate ("Rocks"), + translate ("Items"), + translate ("Weapons"), + translate ("Transport") + }, + }, + { + EV_DECOR4, // pose des blupi + 0, {10, 12, 13, 14, 85, 15, 16, 17, 38, 75, 56}, + 11 + 42 * 2, 190 + 42 * 3, + { + translate ("Delete figure"), + translate ("Tired Blupi"), + translate ("Blupi"), + translate ("Helper robot"), + translate ("Spider"), + translate ("Virus"), + translate ("Bulldozer"), + translate ("Bouncing bomb"), + translate ("Electrocutor"), + translate ("Master robot") + }, + }, + { + EV_DECOR5, // pose les catastrophes + 0, {2, 36, 37}, + 11 + 42 * 2, 190 + 42 * 4, + { + translate ("Delete fire"), + translate ("Starting fire") + }, + }, + { + EV_PHASE_REGION, + 0, {1, 5}, + 11 + 42 * 0, 190 + 42 * 1, + { translate ("Scenery choice") }, + }, + { + EV_PHASE_MUSIC, + 0, {1, 44}, + 11 + 42 * 0, 190 + 42 * 2, + { translate ("Music choice") }, + }, + { + EV_PHASE_BUTTON, + 0, {1, 46}, + 11 + 42 * 0, 190 + 42 * 3, + { translate ("Available buttons") }, + }, + { + EV_PHASE_TERM, + 0, {1, 45}, + 11 + 42 * 0, 190 + 42 * 4, + { translate ("Ending conditions") }, + }, + { + EV_PHASE_INFO, + 0, {1, 40}, + 11 + 42 * 0, 424, + { translate ("Quit construction") }, + }, + { + EV_PHASE_UNDO, + 0, {1, 87}, + 11 + 42 * 2, 424, + { translate ("Cancel last operation") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_BUTTON, + "button.png", + "back-build.png", + CPixmap::Mode::FIX_REVERSABLE, + true, + { + { + EV_BUTTON1, // stop + 0, {1, 40}, + 170 + 42 * 0, 30 + 52 * 0, + { translate ("Stop") }, + }, + { + EV_BUTTON0, // go + 0, {1, 24}, + 170 + 42 * 1, 30 + 52 * 0, + { translate ("Go") }, + }, + { + EV_BUTTON3, // carry + 0, {1, 30}, + 170 + 42 * 3, 30 + 52 * 0, + { translate ("Take") }, + }, + { + EV_BUTTON4, // depose + 0, {1, 31}, + 170 + 42 * 4, 30 + 52 * 0, + { translate ("Drop") }, + }, + { + EV_BUTTON32, // répète + 0, {1, 100}, + 170 + 42 * 6, 30 + 52 * 0, + { translate ("Repeat") }, + }, + + { + EV_BUTTON5, // abat + 0, {1, 22}, + 170 + 42 * 0, 30 + 52 * 1, + { translate ("Cut down a tree") }, + }, + { + EV_BUTTON16, // abat n + 0, {1, 42}, + 170 + 42 * 1, 30 + 52 * 1, + { translate ("Cut down trees") }, + }, + { + EV_BUTTON6, // roc + 0, {1, 27}, + 170 + 42 * 3, 30 + 52 * 1, + { translate ("Carve a rock") }, + }, + { + EV_BUTTON17, // roc n + 0, {1, 43}, + 170 + 42 * 4, 30 + 52 * 1, + { translate ("Carve rocks") }, + }, + { + EV_BUTTON22, // fleurs + 0, {1, 54}, + 170 + 42 * 6, 30 + 52 * 1, + { translate ("Make bunch of flowers") }, + }, + { + EV_BUTTON23, // fleurs n + 0, {1, 55}, + 170 + 42 * 7, 30 + 52 * 1, + { translate ("Make bunches of flowers") }, + }, + + { + EV_BUTTON9, // build2 (couveuse) + 0, {1, 25}, + 170 + 42 * 0, 30 + 52 * 2, + { translate ("Incubator") }, + }, + { + EV_BUTTON15, // palis + 0, {1, 26}, + 170 + 42 * 1, 30 + 52 * 2, + { translate ("Palisade") }, + }, + { + EV_BUTTON18, // pont + 0, {1, 23}, + 170 + 42 * 2, 30 + 52 * 2, + { translate ("Bridge") }, + }, + { + EV_BUTTON25, // bateau + 0, {1, 58}, + 170 + 42 * 3, 30 + 52 * 2, + { translate ("Boat") }, + }, + { + EV_BUTTON13, // build6 (téléporteur) + 0, {1, 101}, + 170 + 42 * 4, 30 + 52 * 2, + { translate ("Teleporter") }, + }, + { + EV_BUTTON14, // mur + 0, {1, 20}, + 170 + 42 * 6, 30 + 52 * 2, + { translate ("Wall") }, + }, + { + EV_BUTTON19, // tour + 0, {1, 33}, + 170 + 42 * 7, 30 + 52 * 2, + { translate ("Protection tower") }, + }, + + { + EV_BUTTON8, // build1 (cabane) + 0, {1, 19}, + 170 + 42 * 0, 30 + 52 * 3, + { translate ("Garden shed") }, + }, + { + EV_BUTTON7, // cultive + 0, {1, 28}, + 170 + 42 * 1, 30 + 52 * 3, + { translate ("Grow tomatoes") }, + }, + { + EV_BUTTON2, // mange + 0, {1, 32}, + 170 + 42 * 2, 30 + 52 * 3, + { translate ("Eat") }, + }, + + { + EV_BUTTON10, // build3 (laboratoire) + 0, {1, 35}, + 170 + 42 * 0, 30 + 52 * 4, + { translate ("Laboratory") }, + }, + { + EV_BUTTON21, // laboratoire + 0, {1, 39}, + 170 + 42 * 1, 30 + 52 * 4, + { translate ("Transform") }, + }, + { + EV_BUTTON20, // boit + 0, {1, 34}, + 170 + 42 * 2, 30 + 52 * 4, + { translate ("Drink") }, + }, + { + EV_BUTTON24, // dynamite + 0, {1, 41}, + 170 + 42 * 3, 30 + 52 * 4, + { translate ("Blow up") }, + }, + + { + EV_BUTTON27, // drapeau + 0, {1, 64}, + 170 + 42 * 0, 30 + 52 * 5, + { translate ("Prospect for iron") }, + }, + { + EV_BUTTON11, // build4 (mine) + 0, {1, 61}, + 170 + 42 * 1, 30 + 52 * 5, + { translate ("Mine") }, + }, + { + EV_BUTTON28, // extrait + 0, {1, 62}, + 170 + 42 * 2, 30 + 52 * 5, + { translate ("Extract iron") }, + }, + { + EV_BUTTON12, // build5 (usine) + 0, {1, 59}, + 170 + 42 * 4, 30 + 52 * 5, + { translate ("Workshop") }, + }, + { + EV_BUTTON29, // fabrique jeep + 0, {1, 65}, + 170 + 42 * 5, 30 + 52 * 5, + { translate ("Make a Jeep") }, + }, + { + EV_BUTTON30, // fabrique mine + 0, {1, 63}, + 170 + 42 * 6, 30 + 52 * 5, + { translate ("Make a time bomb") }, + }, + { + EV_BUTTON34, // fabrique armure + 0, {1, 106}, + 170 + 42 * 7, 30 + 52 * 5, + { translate ("Make armour") }, + }, + { + EV_BUTTON31, // fabrique disciple + 0, {1, 83}, + 170 + 42 * 8, 30 + 52 * 5, + { translate ("Make a helper robot") }, + }, + { + EV_PHASE_BUILD, + 0, {1, 50}, + 11, 424, + { translate ("Finish") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_TERM, + "term.png", + "back-build.png", + CPixmap::Mode::FIX_REVERSABLE, + true, + { + { + EV_BUTTON8, // home blupi + 0, {1, 81}, + 170 + 42 * 0, 30 + 42 * 0, + { translate ("Blupi in house") }, + }, + { + EV_BUTTON9, // kill robots + 0, {1, 57}, + 170 + 42 * 1, 30 + 42 * 0, + { translate ("No more enemies") }, + }, + { + EV_BUTTON3, // stop fire + 0, {1, 37}, + 170 + 42 * 2, 30 + 42 * 0, + { translate ("Fire out") }, + }, + { + EV_BUTTON1, // hach blupi + 0, {1, 14}, + 170 + 42 * 0, 30 + 42 * 2, + { translate ("Blupi on striped paving stones") }, + }, + { + EV_BUTTON2, // hach planche + 0, {1, 22}, + 170 + 42 * 1, 30 + 42 * 2, + { translate ("Planks on striped paving stones") }, + }, + { + EV_BUTTON10, // hach tomate + 0, {1, 28}, + 170 + 42 * 2, 30 + 42 * 2, + { translate ("Tomatoes on striped paving stones") }, + }, + { + EV_BUTTON11, // hach métal + 0, {1, 84}, + 170 + 42 * 3, 30 + 42 * 2, + { translate ("Platinium on striped paving stones") }, + }, + { + EV_BUTTON12, // hach robot + 0, {1, 94}, + 170 + 42 * 4, 30 + 42 * 2, + { translate ("Robot on striped paving stones") }, + }, + { + EV_BUTTON4, // - min blupi + 0, {1, 50}, + 170 + 42 * 0, 30 + 42 * 4, + { "(-)" }, + }, + { + EV_BUTTON5, // + min blupi + 0, {1, 51}, + 170 + 42 * 1, 30 + 42 * 4, + { "(+)" }, + }, + { + EV_BUTTON6, // - max blupi + 0, {1, 50}, + 170 + 42 * 0, 30 + 42 * 5, + { "(-)" }, + }, + { + EV_BUTTON7, // + max blupi + 0, {1, 51}, + 170 + 42 * 1, 30 + 42 * 5, + { "(+)" }, + }, + { + EV_PHASE_BUILD, + 0, {1, 50}, + 11, 424, + { translate ("Finish") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_MUSIC, + "music.png", + "back-build.png", + CPixmap::Mode::FIX_REVERSABLE, + true, + { + { + EV_BUTTON1, + 0, {1, 40}, + 11, 101, + { translate ("No music") }, + }, + { + EV_BUTTON2, + 0, {1, 44}, + 170 + 42 * 0, 30 + 42 * 0, + { translate ("Music number 1") }, + }, + { + EV_BUTTON3, + 0, {1, 44}, + 170 + 42 * 0, 30 + 42 * 1, + { translate ("Music number 2") }, + }, + { + EV_BUTTON4, + 0, {1, 44}, + 170 + 42 * 0, 30 + 42 * 2, + { translate ("Music number 3") }, + }, + { + EV_BUTTON5, + 0, {1, 44}, + 170 + 42 * 0, 30 + 42 * 3, + { translate ("Music number 4") }, + }, + { + EV_BUTTON6, + 0, {1, 44}, + 170 + 42 * 0, 30 + 42 * 4, + { translate ("Music number 5") }, + }, + { + EV_BUTTON7, + 0, {1, 44}, + 170 + 42 * 0, 30 + 42 * 5, + { translate ("Music number 6") }, + }, + { + EV_BUTTON8, + 0, {1, 44}, + 170 + 42 * 0, 30 + 42 * 6, + { translate ("Music number 7") }, + }, + { + EV_BUTTON9, + 0, {1, 44}, + 170 + 42 * 0, 30 + 42 * 7, + { translate ("Music number 8") }, + }, + { + EV_BUTTON10, + 0, {1, 44}, + 170 + 42 * 0, 30 + 42 * 8, + { translate ("Music number 9") }, + }, + { + EV_BUTTON11, + 0, {1, 44}, + 170 + 42 * 0, 30 + 42 * 9, + { translate ("Music number 10") }, + }, + { + EV_PHASE_BUILD, + 0, {1, 50}, + 11, 424, + { translate ("Finish") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_REGION, + "region.png", + "back-build.png", + CPixmap::Mode::FIX_REVERSABLE, + true, + { + { + EV_BUTTON1, // normal + 0, {0}, + 220, 60, + { translate ("Prairie") }, + }, + { + EV_BUTTON4, // sapins + 0, {0}, + 220, 170, + { translate ("Forest") }, + }, + { + EV_BUTTON2, // palmiers + 0, {0}, + 220, 280, + { translate ("Desert") }, + }, + { + EV_BUTTON3, // hivers + 0, {0}, + 220, 390, + { translate ("Forest under snow") }, + }, + { + EV_PHASE_BUILD, + 0, {1, 50}, + 11, 424, + { translate ("Finish") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_PLAYMOVIE, + "movie.png", + "", + CPixmap::Mode::FIX, + false, + { + { + 0 + }, + }, + }, + + { + EV_PHASE_WINMOVIE, + "movie.png", + "", + CPixmap::Mode::FIX, + false, + { + { + 0 + }, + }, + }, + + { + EV_PHASE_H0MOVIE, + "movie.png", + "", + CPixmap::Mode::FIX, + false, + { + { + 0 + }, + }, + }, + + { + EV_PHASE_H1MOVIE, + "movie.png", + "", + CPixmap::Mode::FIX, + false, + { + { + 0 + }, + }, + }, + + { + EV_PHASE_H2MOVIE, + "movie.png", + "", + CPixmap::Mode::FIX, + false, + { + { + 0 + }, + }, + }, + + { + EV_PHASE_BYE, + "bye.png", + "back-bye.png", + CPixmap::Mode::FIX, + false, + { + { + 0 + }, + }, + }, + + { + EV_PHASE_INSERT, + "insert.png", + "", + CPixmap::Mode::FIX, + false, + { + { + EV_PHASE_INIT, + 0, {1, 40}, + 16, 424, + { translate ("Quit Planet Blupi") }, + }, + { + 0 + }, + }, + }, + + { + EV_PHASE_SETTINGS, + "setup00.png", + "back-setup.png", + CPixmap::Mode::FIX, + false, + { + { + EV_BUTTON1, + 0, {1, 50}, + 54, 330, + { translate ("Previous language") }, + }, + { + EV_BUTTON2, + 0, {1, 51}, + 54 + 40, 330, + { translate ("Next language") }, + }, + { + EV_BUTTON3, + 0, {1, 50}, + 169, 330, + { translate ("Fullscreen") }, + }, + { + EV_BUTTON4, + 0, {1, 51}, + 169 + 40, 330, + { translate ("Windowed") }, + }, + { + EV_BUTTON5, + 0, {1, 50}, + 284, 330, + { "" /* dynamic */ }, + }, + { + EV_BUTTON6, + 0, {1, 51}, + 284 + 40, 330, + { "" /* dynamic */ }, + }, + { + EV_BUTTON7, + 0, {1, 50}, + 399, 330, + { translate ("Use Ogg music") }, + }, + { + EV_BUTTON8, + 0, {1, 51}, + 399 + 40, 330, + { translate ("Use Midi music (original)") }, + }, + { + EV_BUTTON9, + 0, {1, 50}, + 514, 330, + { translate ("Disable anti-aliasing") }, + }, + { + EV_BUTTON10, + 0, {1, 51}, + 514 + 40, 330, + { translate ("Enable anti-aliasing") }, + }, + { + EV_PHASE_INIT, + 0, {1, 40}, + 42 + 42 * 0, 433, + { translate ("Finish") }, + }, + { + 0 + }, + }, + }, + + { + 0 + } +}; +// clang-format on + +///////////////////////////////////////////////////////////////////////////// + +// Constructeur. + +CEvent::CEvent () +{ + Sint32 i; + + m_exercice = 0; + m_mission = 0; + m_private = 0; + m_maxMission = 0; + m_phase = 0; + m_index = -1; + m_bSchool = false; + m_bPrivate = false; + m_bAccessBuild = false; + m_bRunMovie = false; + m_bBuildModify = false; + m_bMouseDown = false; + m_oldMousePos.x = 0; + m_oldMousePos.y = 0; + m_mouseSprite = SPRITE_ARROW; + m_bFillMouse = false; + m_bWaitMouse = false; + m_bHideMouse = false; + m_rankCheat = -1; + m_posCheat = 0; + m_speed = 1; + m_bMovie = true; + m_bSpeed = false; + m_bHelp = false; + m_bAllMissions = false; + m_scrollSpeed = 1; + m_scrollSpeedPrev = -1; + m_bPause = false; + m_bShift = false; + m_shiftPhase = 0; + m_movieToStart[0] = 0; + m_bInfoHelp = false; + m_bDemoRec = false; + m_bDemoPlay = false; + m_pDemoBuffer = nullptr; + m_bStartRecording = false; + m_demoTime = 0; + m_keymod = 0; + m_posHelpButton = {-1, -1}; + m_pPixmap = nullptr; + m_pDecor = nullptr; + m_pSound = nullptr; + m_pMovie = nullptr; + m_bMenu = false; + m_bHili = false; + m_demoIndex = 0; + m_demoEnd = 0; + m_bHiliInfoButton = false; + m_bHiliHelpButton = false; + + memset (m_textToolTips, 0, sizeof (m_textToolTips)); + memset (m_libelle, 0, sizeof (m_libelle)); + + for (i = 0; i < MAXBUTTON; i++) + m_lastFloor[i] = 0; + + for (i = 0; i < MAXBUTTON; i++) + m_lastObject[i] = 0; + + for (i = 0; i < MAXBUTTON; i++) + m_lastHome[i] = 0; + + // TODO: should be dynamic by looking in the locale directory + m_Languages.push_back (Language::en); + m_Languages.push_back (Language::en_US); + m_Languages.push_back (Language::fr); + m_Languages.push_back (Language::de); + m_Languages.push_back (Language::it); + m_Languages.push_back (Language::pl); + m_Languages.push_back (Language::tr); + m_Languages.push_back (Language::pt); + m_Languages.push_back (Language::he); + + this->m_LangStart = GetLocale (); + + if (this->m_LangStart == "en_US") + m_Lang = m_Languages.begin () + 1; + else if (this->m_LangStart == "fr") + m_Lang = m_Languages.begin () + 2; + else if (this->m_LangStart == "de") + m_Lang = m_Languages.begin () + 3; + else if (this->m_LangStart == "it") + m_Lang = m_Languages.begin () + 4; + else if (this->m_LangStart == "pl") + m_Lang = m_Languages.begin () + 5; + else if (this->m_LangStart == "tr") + m_Lang = m_Languages.begin () + 6; + else if (this->m_LangStart == "pt") + m_Lang = m_Languages.begin () + 7; + else if (this->m_LangStart == "he") + m_Lang = m_Languages.begin () + 8; + else + m_Lang = m_Languages.begin (); + + m_updateBlinking = 0; + + this->shiftDirection = 0; + this->statDisabled = false; +} + +// Destructeur. + +CEvent::~CEvent () +{ + WriteInfo (); // lit le fichier "info.blp" +} + +bool +CEvent::IsDemoPlaying () +{ + return this->m_bDemoPlay; +} + +// Retourne la position de la souris. + +Point +CEvent::GetMousePos () +{ + Point pos; + Sint32 x, y; + + SDL_GetMouseState (&x, &y); + pos.x = x; + pos.y = y; + + return pos; +} + +// Initialise le mode full screen ou non. + +void +CEvent::SetFullScreen (bool bFullScreen, double prevScale) +{ + g_bFullScreen = bFullScreen; + + if (Platform::getType () == Platform::Type::JS) + return; + + int x, y; + SDL_GetMouseState (&x, &y); + this->m_pPixmap->FromDisplayToGame (x, y, prevScale); + + int displayIndex = SDL_GetWindowDisplayIndex (g_window); +#ifdef _WIN32 + if (g_zoom == 2) + displayIndex = 0; +#endif /* _WIN32 */ + + SDL_RenderClear (g_renderer); + SDL_RenderPresent (g_renderer); + + if (g_bFullScreen && g_zoom == 2) + { + int displays = SDL_GetNumVideoDisplays (); + + std::vector displayBounds; + for (int i = 0; i < displays; i++) + { + displayBounds.push_back (SDL_Rect ()); + SDL_GetDisplayBounds (i, &displayBounds.back ()); + } + + /* It seems that the fullscreen switching works better when the window + * is at the top left corner of the current display. + */ + SDL_SetWindowPosition ( + g_window, displayBounds[displayIndex].x, displayBounds[displayIndex].y); + } + + SDL_SetWindowFullscreen ( + g_window, bFullScreen ? (g_zoom == 1 ? SDL_WINDOW_FULLSCREEN_DESKTOP + : SDL_WINDOW_FULLSCREEN) + : 0); + SDL_SetWindowBordered (g_window, bFullScreen ? SDL_FALSE : SDL_TRUE); + SDL_SetWindowGrab (g_window, bFullScreen ? SDL_TRUE : SDL_FALSE); + + m_pPixmap->LoadCursors (); + + /* Force this update before otherwise the coordinates retrieved with + * the Warp SDL function are corresponding to the previous size. + */ + CEvent::PushUserEvent (EV_UPDATE); + + auto coord = new SDL_Point; // Released by the event handler. + coord->x = x; + coord->y = y; + CEvent::PushUserEvent (EV_WARPMOUSE, coord); +} + +/** + * \brief Change the size of the window. + * + * We use an integer scale to be sure that the pixels are always well formed. + * + * \param[in] newScale - The new scale. + */ +void +CEvent::SetWindowSize (Uint8 newScale) +{ + auto scale = g_zoom; + g_zoom = newScale; + switch (newScale) + { + case 1: + case 2: + SetWindowSize (scale, g_zoom); + break; + + default: + return; + } +} + +/** + * \brief Change the size of the window. + * + * We use an integer scale to be sure that the pixels are always well formed. + * + * \param[in] prevScale - The current scale. + * \param[in] newScale - The new scale. + */ +void +CEvent::SetWindowSize (double prevScale, double newScale) +{ + int x, y; + SDL_GetMouseState (&x, &y); + this->m_pPixmap->FromDisplayToGame (x, y, prevScale); + + if (g_bFullScreen && newScale == 2) + newScale = 1; + + SDL_SetWindowSize (g_window, LXIMAGE () * newScale, LYIMAGE () * newScale); + SDL_RenderClear (g_renderer); + SDL_RenderPresent (g_renderer); + + int displayIndex = SDL_GetWindowDisplayIndex (g_window); + SDL_SetWindowPosition ( + g_window, SDL_WINDOWPOS_CENTERED_DISPLAY (displayIndex), + SDL_WINDOWPOS_CENTERED_DISPLAY (displayIndex)); + SDL_Delay (100); + + m_pPixmap->LoadCursors (); + + if (prevScale == newScale) + return; + + /* Force this update before otherwise the coordinates retrieved with + * the Warp SDL function are corresponding to the previous size. + */ + CEvent::PushUserEvent (EV_UPDATE); + + auto coord = new SDL_Point; // Released by the event handler. + coord->x = x; + coord->y = y; + CEvent::PushUserEvent (EV_WARPMOUSE, coord); +} + +// Crée le gestionnaire d'événements. + +void +CEvent::Create ( + CPixmap * pPixmap, CDecor * pDecor, CSound * pSound, CMovie * pMovie) +{ + Point pos; + + m_pPixmap = pPixmap; + m_pDecor = pDecor; + m_pSound = pSound; + m_pMovie = pMovie; + + ReadInfo (); // lit le fichier "info.blp" + + pos.x = 10; + pos.y = 158; + m_jauges[0].Create (m_pPixmap, m_pSound, pos, 1); + + pos.y += DIMJAUGEY + 2; + m_jauges[1].Create (m_pPixmap, m_pSound, pos, 3); +} + +// Retourne l'index d'un bouton. + +Sint32 +CEvent::GetButtonIndex (Sint32 button) +{ + int i = 0; + + if (m_index < 0) + return -1; + + while (table[m_index].buttons[i].message != 0) + { + if ((Uint32) button == table[m_index].buttons[i].message) + return i; + i++; + } + + return -1; +} + +Sint32 +CEvent::GetState (Sint32 button) +{ + Sint32 index; + + index = GetButtonIndex (button); + if (index < 0) + return 0; + + return m_buttons[index].GetState (); +} + +void +CEvent::SetState (Sint32 button, Sint32 state) +{ + Sint32 index; + + index = GetButtonIndex (button); + if (index < 0) + return; + + m_buttons[index].SetState (state); +} + +bool +CEvent::GetEnable (Sint32 button) +{ + Sint32 index; + + index = GetButtonIndex (button); + if (index < 0) + return 0; + + return m_buttons[index].GetEnable (); +} + +void +CEvent::SetEnable (Sint32 button, bool bEnable) +{ + Sint32 index; + + index = GetButtonIndex (button); + if (index < 0) + return; + + m_buttons[index].SetEnable (bEnable); +} + +bool +CEvent::GetHide (Sint32 button) +{ + Sint32 index; + + index = GetButtonIndex (button); + if (index < 0) + return 0; + + return m_buttons[index].GetHide (); +} + +void +CEvent::SetHide (Sint32 button, bool bHide) +{ + Sint32 index; + + index = GetButtonIndex (button); + if (index < 0) + return; + + m_buttons[index].SetHide (bHide); +} + +Sint32 +CEvent::GetMenu (Sint32 button) +{ + Sint32 index; + + index = GetButtonIndex (button); + if (index < 0) + return 0; + + return m_buttons[index].GetMenu (); +} + +void +CEvent::SetMenu (Sint32 button, Sint32 menu) +{ + Sint32 index; + + index = GetButtonIndex (button); + if (index < 0) + return; + + m_buttons[index].SetMenu (menu); +} + +// Crée tous les boutons nécessaires à la phase en cours. + +bool +CEvent::CreateButtons (Sint32 phase) +{ + Sint32 i = 0, message; + Point pos; + + if (m_index < 0) + return false; + + while (table[m_index].buttons[i].message != 0) + { + pos.x = table[m_index].buttons[i].x; + pos.y = table[m_index].buttons[i].y; + message = table[m_index].buttons[i].message; + + auto isRightReading = + ((message == EV_PHASE_INIT || message == EV_PHASE_PLAY || + message == EV_SETUP_EXIT) || + (phase != EV_PHASE_SETTINGS && phase != EV_PHASE_SETUP && + phase != EV_PHASE_SETUPp)) && + IsRightReading (); + + if (isRightReading) + pos.x = LXIMAGE () - pos.x - DIMBUTTONX; + + if ( + phase != EV_PHASE_PLAY && phase != EV_PHASE_BUILD && + phase != EV_PHASE_INIT) + pos.x = isRightReading ? pos.x - LXOFFSET () : pos.x + LXOFFSET (); + + if (m_bPrivate) + { + if (message == EV_PHASE_SKILL1) + { + pos.x = 117 + LXOFFSET (); + pos.y = 115; + if (isRightReading) + pos.x = LXIMAGE () - pos.x - DIMBUTTONX; + } + if (message == EV_PHASE_SKILL2) + { + pos.x = 117 + LXOFFSET (); + pos.y = 115 + 42; + if (isRightReading) + pos.x = LXIMAGE () - pos.x - DIMBUTTONX; + } + } + + m_buttons[i].Create ( + m_pPixmap, m_pSound, pos, table[m_index].buttons[i].type, + table[m_index].buttons[i].iconMenu + 1, + table[m_index].buttons[i].iconMenu[0], table[m_index].buttons[i].toolTips, + m_pDecor->GetRegion (), message, isRightReading); + i++; + } + + return true; +} + +// Ajoute un cheat-code dans un buffer. + +void +AddCheatCode (char * pDst, char * pSrc) +{ + Sint32 i; + size_t j; + + if (pDst[0] != 0) + strcat (pDst, " / "); + + i = 0; + j = strlen (pDst); + while (pSrc[i] != 0) + pDst[j++] = pSrc[i++]; + pDst[j] = 0; +} + +void +CEvent::SetUpdateVersion (const std::string & version) +{ + this->m_updateVersion = version; +} + +// Dessine un texte multi-lignes centré. + +void +CEvent::DrawTextCenter (const char * text, Sint32 x, Sint32 y, Sint32 font) +{ + Point pos; + pos.x = x; + pos.y = y; + ::DrawTextCenter (m_pPixmap, pos, text, font); +} + +// Dessine tous les boutons de la phase en cours. + +bool +CEvent::DrawButtons () +{ + Sint32 i; + Sint32 levels[2]; + Sint32 types[2]; + Sint32 world, time, lg, button, volume, pente, icon; + char res[100]; + char text[100]; + Point pos; + Rect rect; + bool bEnable; + + if ( + (m_phase == EV_PHASE_PLAY) || + (m_phase != EV_PHASE_PLAY && m_phase != EV_PHASE_INSERT && + m_phase != EV_PHASE_INTRO1 && m_phase != EV_PHASE_BYE)) + { + text[0] = 0; + if (m_bAllMissions) + AddCheatCode (text, cheat_code[3]); + if (m_bSpeed) + AddCheatCode (text, cheat_code[4]); + if (m_bHelp) + AddCheatCode (text, cheat_code[5]); + if (m_pDecor->GetInvincible ()) + AddCheatCode (text, cheat_code[6]); + if (m_pDecor->GetSuper ()) + AddCheatCode (text, cheat_code[7]); + + if (text[0]) + { + pos.x = 2; + pos.y = 2; + rect.left = pos.x; + rect.right = pos.x + 300; + rect.top = pos.y; + rect.bottom = pos.y + DIMLITTLEY; + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawText (m_pPixmap, pos, text, FONTLITTLE); + } + } + + if (m_phase == EV_PHASE_INIT) + { + snprintf ( + res, sizeof (res), "%s %u.%u.%u%s", gettext ("Version"), PB_VERSION_MAJOR, + PB_VERSION_MINOR, PB_VERSION_PATCH, PB_VERSION_EXTRA); + pos.x = IsRightReading () ? 4 + GetTextWidth (res, FONTLITTLE) + : LXIMAGE () - GetTextWidth (res, FONTLITTLE) - 4; + pos.y = 465; + DrawText (m_pPixmap, pos, res, FONTLITTLE); + + if (!this->m_updateVersion.empty () && this->m_updateBlinking++ % 80 < 40) + { + pos.x = 70 + LXOFFSET (); + pos.y = 465; + snprintf ( + res, sizeof (res), + gettext ("New version available for download on www.blupi.org (v%s)"), + this->m_updateVersion.c_str ()); + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawText (m_pPixmap, pos, res, FONTLITTLE); + } + } + + if (m_phase == EV_PHASE_SETUP || m_phase == EV_PHASE_SETUPp) + { + bEnable = true; + if (m_speed == 1) + bEnable = false; + SetEnable (EV_BUTTON1, bEnable); + bEnable = true; + if (m_speed >= (m_bSpeed ? 8 : 2)) + bEnable = false; + SetEnable (EV_BUTTON2, bEnable); + + volume = m_pSound->GetAudioVolume (); + bEnable = true; + if (volume == 0) + bEnable = false; + SetEnable (EV_BUTTON3, bEnable); + bEnable = true; + if (volume >= MAXVOLUME) + bEnable = false; + SetEnable (EV_BUTTON4, bEnable); + + volume = m_pSound->GetMidiVolume (); + bEnable = true; + if (volume == 0) + bEnable = false; + SetEnable (EV_BUTTON5, bEnable); + bEnable = true; + if (volume >= MAXVOLUME) + bEnable = false; + SetEnable (EV_BUTTON6, bEnable); + + if (m_pMovie->GetEnable ()) + { + SetEnable (EV_BUTTON7, m_bMovie); + SetEnable (EV_BUTTON8, !m_bMovie); + } + else + { + SetEnable (EV_BUTTON7, false); + SetEnable (EV_BUTTON8, false); + } + + bEnable = true; + if (m_scrollSpeed == 0) + bEnable = false; + SetEnable (EV_BUTTON9, bEnable); + bEnable = true; + if (m_scrollSpeed >= 3) + bEnable = false; + SetEnable (EV_BUTTON10, bEnable); + } + + /* Check if both music formats are available */ + auto ogg = this->IsBaseMusicAvailable (1, "ogg"); + auto mid = this->IsBaseMusicAvailable (1, "mid"); + + if (m_phase == EV_PHASE_SETTINGS) + { + SetEnable (EV_BUTTON1, m_Lang != m_Languages.begin ()); + SetEnable (EV_BUTTON2, m_Lang != m_Languages.end () - 1); + + SetEnable (EV_BUTTON3, !g_bFullScreen); + SetEnable (EV_BUTTON4, g_bFullScreen); + + SetEnable (EV_BUTTON5, g_zoom > 1); + SetEnable (EV_BUTTON6, g_zoom < 2); + + SetEnable (EV_BUTTON7, g_restoreMidi && mid && ogg); + SetEnable (EV_BUTTON8, !g_restoreMidi && mid && ogg); + + SetEnable (EV_BUTTON9, g_bFullScreen && g_zoom == 1 && g_renderQuality); + SetEnable (EV_BUTTON10, g_bFullScreen && g_zoom == 1 && !g_renderQuality); + + table[m_index].buttons[4].toolTips[0] = + g_bFullScreen ? gettext ("Desktop mode") : gettext ("Reduce window size"); + table[m_index].buttons[5].toolTips[0] = + g_bFullScreen ? gettext ("Legacy mode (640x480)") + : gettext ("Increase window size"); + } + + assert (m_index >= 0); + + // Dessine les boutons. + i = 0; + while (table[m_index].buttons[i].message != 0) + { + m_buttons[i].Draw (); + ++i; + } + + if (m_phase == EV_PHASE_PLAY) + { + // Dessine les jauges. + m_pDecor->GetLevelJauge (levels, types); + + for (i = 0; i < 2; i++) + { + if (levels[i] < 0) + m_jauges[i].SetHide (true); + else + { + m_jauges[i].SetHide (false); + m_jauges[i].SetLevel (levels[i]); + m_jauges[i].SetType (types[i]); + } + m_jauges[i].Draw (); + } + + // Dessine le menu. + if (m_menu.IsExist ()) + { + m_pDecor->BlupiGetButtons ( + m_menuPos, m_menuNb, m_menuButtons, m_menuErrors, m_menuTexts, + m_menuPerso); + m_menu.Update (m_menuNb, m_menuButtons, m_menuErrors, m_menuTexts); + + button = m_menu.GetSel (); + m_pDecor->CelHiliButton (m_menuCel, button); + } + m_menu.Draw (); + + auto offset = IsRightReading () ? POSDRAWX + DIMDRAWX : 0; + + // Dessine la rose des vents. + if (!m_bPause && !m_bDemoPlay) + { + DrawTextCenter (gettext ("N"), (10 + 134) / 2 + offset, 17); + DrawTextCenter (gettext ("S"), (10 + 134) / 2 + offset, 126); + DrawTextCenter (gettext ("W"), 14 + offset, 70); + DrawTextCenter (gettext ("E"), 129 + offset, 70); + } + + // Dessine la pause. + if (m_bPause) + DrawTextCenter (gettext ("Game paused"), (10 + 134) / 2 + offset, 20); + else + { + if (m_bDemoRec) // recording demo ? + DrawTextCenter (gettext ("REC"), (10 + 38) / 2 + offset, 20, FONTRED); + if (m_bDemoPlay) // playing demo ? + DrawTextCenter (gettext ("Demo"), (10 + 134) / 2 + offset, 20, FONTRED); + } + + // Dessine la vitesse. + pos.x = IsRightReading () ? LXIMAGE () - 64 : 64; + pos.y = LYIMAGE () - 15; + rect.left = pos.x; + rect.right = pos.x + 20; + rect.top = pos.y; + rect.bottom = pos.y + 15; + m_pPixmap->DrawPart (-1, CHBACK, pos, rect); // dessine le fond + if (m_speed > 1) + { + snprintf (res, sizeof (res), "x%d", m_speed); + DrawText (m_pPixmap, pos, res); + } + + // Dessine le bouton pour les infos. + if (m_pDecor->GetInfoMode ()) // infos visibles ? + { + lg = m_pDecor->GetInfoHeight (); + + pos.x = POSDRAWX; + pos.y = 0; + rect.left = POSDRAWX; + rect.right = POSDRAWX + DIMDRAWX; + rect.top = 0; + rect.bottom = lg; + m_pPixmap->DrawPart (-1, CHBACK, pos, rect); + + pos.x = POSDRAWX; + pos.y = lg; + rect.left = POSDRAWX; + rect.right = POSDRAWX + DIMDRAWX; + rect.top = 0; + rect.bottom = POSDRAWY; + m_pPixmap->DrawPart (-1, CHBACK, pos, rect); + + pos.x = POSDRAWX_ + 20; + pos.y = POSDRAWY + 4; + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawTextRect (m_pPixmap, pos, m_libelle, 0, FONTLITTLE, 1); + pos.x = POSDRAWX_ + DIMDRAWX / 2 + 20; + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawTextRect (m_pPixmap, pos, m_libelle, 0, FONTLITTLE, 2); + + pos.x = POSDRAWX + DIMDRAWX / 2 - DIMBUTTONX / 2; + pos.y = lg - 14; + m_pPixmap->DrawIcon (-1, CHBUTTON, m_bHiliInfoButton ? 73 : 72, pos); + + if (IsHelpHide ()) // bouton pour aide ? + m_posHelpButton.x = -1; + else + { + m_posHelpButton.x = POSDRAWX + DIMDRAWX - DIMBUTTONX - 2; + m_posHelpButton.y = lg - DIMBUTTONY - 2; + if (IsRightReading ()) + m_posHelpButton.x = POSDRAWX + 2; + m_pPixmap->DrawIcon ( + -1, CHBUTTON, m_bHiliHelpButton ? 2 : 0, m_posHelpButton); + if (m_bInfoHelp) + icon = 86; // livre + else + icon = 92; // aide + m_pPixmap->DrawIcon (-1, CHBUTTON, icon, m_posHelpButton); + } + } + else // infos cachées ? + { + pos.x = POSDRAWX + DIMDRAWX / 2 - DIMBUTTONX / 2; + pos.y = -12; + if (IsRightReading ()) + m_posHelpButton.x = POSDRAWX + 2; + m_pPixmap->DrawIcon (-1, CHBUTTON, m_bHiliInfoButton ? 75 : 74, pos); + } + m_posInfoButton = pos; + } + + // Dessine les noms des fichiers. + if ( + m_phase == EV_PHASE_READ || m_phase == EV_PHASE_WRITE || + m_phase == EV_PHASE_WRITEp) + { + if (m_phase == EV_PHASE_READ) + snprintf (res, sizeof (res), "%s", gettext ("Open another game")); + else + snprintf (res, sizeof (res), "%s", gettext ("Save this game")); + + pos.x = 420 + LXOFFSET (); + pos.y = 8; + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawText (m_pPixmap, pos, res); + + for (i = 0; i < 10; i++) + { + world = m_fileWorld[i]; + time = m_fileTime[i]; + + snprintf (text, sizeof (text), "%d", i + 1); + lg = GetTextWidth (text); + pos.x = (420 + 460) / 2 - lg / 2 + LXOFFSET (); + pos.y = 30 + 12 + 42 * i; + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawText (m_pPixmap, pos, text, FONTSLIM); + + pos.x = 420 + 50 + LXOFFSET (); + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + + if (world >= 0) + { + if (world >= 200) + snprintf ( + text, sizeof (text), gettext ("construction %d, time %d"), + (world - 200) + 1, time / 100); + else if (world >= 100) + snprintf ( + text, sizeof (text), gettext ("mission %d, time %d"), + (world - 100) + 1, time / 100); + else + snprintf ( + text, sizeof (text), gettext ("training %d, time %d"), world + 1, + time / 100); + + DrawText (m_pPixmap, pos, text); // partie x, temps t + } + else + DrawText (m_pPixmap, pos, gettext ("free slot"), FONTRED); // libre + } + } + + // Dessine les réglages pour la fin de la partie. + if (m_phase == EV_PHASE_TERM) + { + Term * pTerm = m_pDecor->GetTerminated (); + + auto x = (10 + 134) / 2 + LXOFFSET (); + if (IsRightReading ()) + x = LXIMAGE () - x; + DrawTextCenter (gettext ("Ending conditions"), x, 20); + + pos.x = 170 + 42 * 2 + 4 + LXOFFSET (); + pos.y = 30 + 12 + 42 * 4; + snprintf ( + text, sizeof (text), gettext ("Lost if less than %d Blupi"), + pTerm->nbMinBlupi); + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawText (m_pPixmap, pos, text); + + pos.x = 170 + 42 * 2 + 4 + LXOFFSET (); + pos.y = 30 + 12 + 42 * 5; + snprintf ( + text, sizeof (text), gettext ("Impossible to win if less than %d Blupi"), + pTerm->nbMaxBlupi); + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawText (m_pPixmap, pos, text); + } + + // Dessine les textes pour les choix des boutons. + if (m_phase == EV_PHASE_BUTTON) + { + auto x = (10 + 134) / 2 + LXOFFSET (); + if (IsRightReading ()) + x = LXIMAGE () - x; + DrawTextCenter (gettext ("Available buttons"), x, 20); + } + + // Dessine les textes pour le choix des musiques. + if (m_phase == EV_PHASE_MUSIC) + { + auto x = (10 + 134) / 2 + LXOFFSET (); + if (IsRightReading ()) + x = LXIMAGE () - x; + DrawTextCenter (gettext ("Music choice"), x, 20); + } + + // Dessine les textes pour le choix de la région. + if (m_phase == EV_PHASE_REGION) + { + auto x = (10 + 134) / 2 + LXOFFSET (); + if (IsRightReading ()) + x = LXIMAGE () - x; + DrawTextCenter (gettext ("Scenery choice"), x, 20); + } + + // Ajoute "Mission numéro". + if (m_phase == EV_PHASE_INFO) + { + if (m_bSchool) + snprintf (res, sizeof (res), "%s", gettext ("Training number")); + else + snprintf (res, sizeof (res), "%s", gettext ("Mission number")); + + if (m_bPrivate) + snprintf (res, sizeof (res), "%s", gettext ("Construction number")); + + lg = GetTextWidth (res); + pos.x = (140 + 270) / 2 - lg / 2 + LXOFFSET (); + pos.y = 70; + if (m_bSchool) + pos.x -= 40; + if (m_bPrivate) + pos.x -= 100; + if (m_bPrivate) + pos.y += 14; + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawText (m_pPixmap, pos, res, FONTSLIM); + } + + // Ajoute le texte "Partie interrompue". + if (m_phase == EV_PHASE_STOP) + { + char * text = gettext ("Game paused"); + lg = GetTextWidth (text); + pos.x = (140 + 270) / 2 - lg / 2 + LXOFFSET (); + pos.y = 70; + if (m_bSchool) + pos.x -= 40; + if (m_bPrivate) + pos.x -= 100; + if (m_bPrivate) + pos.y += 14; + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawText (m_pPixmap, pos, text, FONTRED); + } + + // Ajoute le texte "Informations complémentaires". + if (m_phase == EV_PHASE_HELP) + { + char * text = gettext ("Help number"); + lg = GetTextWidth (text); + pos.x = (140 + 270) / 2 - lg / 2 + LXOFFSET (); + pos.y = 70; + if (m_bSchool) + pos.x -= 40; + if (m_bPrivate) + pos.x -= 100; + if (m_bPrivate) + pos.y += 14; + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawText (m_pPixmap, pos, text, FONTRED); + } + + // Ajoute le numéro du monde. + if ( + m_phase == EV_PHASE_INFO || m_phase == EV_PHASE_STOP || + m_phase == EV_PHASE_HELP) + { + if (m_bSchool) + world = m_exercice; + else + world = m_mission; + if (m_bPrivate) + world = m_private; + + lg = GetBignumWidth (world + 1); + lg = IsRightReading () ? -lg : lg; + pos.x = (140 + 270) / 2 - lg / 2 + LXOFFSET (); + pos.y = 100; + if (m_bSchool) + pos.x -= 40; + if (m_bPrivate) + pos.x -= 135; + if (m_bPrivate) + pos.y = 115; + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawBignum (m_pPixmap, pos, world + 1); + } + + // Affiche facile/difficile. + if (m_phase == EV_PHASE_INFO) + { + if (!m_bSchool) + { + std::string text; + if (m_pDecor->GetSkill () == 0) + { + if (m_bPrivate) + { + pos.x = 117 + 50; + pos.y = 115 + 13; + } + else + { + pos.x = 150 + 50; + pos.y = 230 + 13; + } + pos.x += LXOFFSET (); + text = gettext ("Easy"); + } + else if (m_pDecor->GetSkill () == 1) + { + if (m_bPrivate) + { + pos.x = 117 + 50; + pos.y = 115 + 42 + 13; + } + else + { + pos.x = 150 + 50; + pos.y = 230 + 42 + 13; + } + pos.x += LXOFFSET (); + text = gettext ("Difficult"); + } + + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawText (m_pPixmap, pos, text.c_str (), FONTSLIM); + } + } + + // Affiche le libellé de l'énigme. + if ( + m_phase == EV_PHASE_INFO || m_phase == EV_PHASE_STOP || + m_phase == EV_PHASE_HELP || m_phase == EV_PHASE_HISTORY0 || + m_phase == EV_PHASE_HISTORY1) + { + pos.x = 355; + pos.y = 70; + if (m_bSchool) + pos.x -= 20; + if (m_bPrivate) + { + pos.x = 460; + pos.y = 260; + } + if (m_bSchool || m_bPrivate) + pente = 0; + else + pente = 19; + pos.x += LXOFFSET (); + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawTextRect (m_pPixmap, pos, m_libelle, pente, FONTSLIM); + } + + // Affiche le texte lorsque c'est raté. + if (m_phase == EV_PHASE_LOST) + { + const char * list[] = { + gettext ("You have failed, try again..."), + gettext ("No, wrong way ..."), + gettext ("Bang, failed again !"), + gettext ("Another mistake..."), + gettext ("No, not that way !"), + }; + + pos.x = 60 + LXOFFSET (); + pos.y = 443; + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawText (m_pPixmap, pos, list[GetWorld () % 5]); + } + + // Affiche le texte lorsque c'est réussi. + if (m_phase == EV_PHASE_WIN) + { + const char * list[] = { + gettext ("Well done !"), gettext ("Yes, great ..."), + gettext ("Very good."), gettext ("Excellent..."), + gettext ("Mission over..."), + }; + + pos.x = 60 + LXOFFSET (); + pos.y = 443; + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawText (m_pPixmap, pos, list[GetWorld () % 5]); + } + + // Show the ending text when the game is finished. + if (m_phase == EV_PHASE_LASTWIN) + { + char * text; + if (m_bSchool) + text = gettext ("Now go on mission."); + else + text = gettext ("Very good, success on all missions !"); + + if (m_bPrivate) + text = gettext ("Last construction resolved !"); + + pos.x = 60 + LXOFFSET (); + pos.y = 443; + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + DrawText (m_pPixmap, pos, text); + } + + // Draw the game settings. + if (m_phase == EV_PHASE_SETUP || m_phase == EV_PHASE_SETUPp) + { + DrawTextCenter (gettext ("Global game\nspeed"), 54 + 40 + LXOFFSET (), 80); + DrawTextCenter ( + gettext ("Scroll speed\nwith mouse"), 169 + 40 + LXOFFSET (), 80); + DrawTextCenter ( + gettext ("Sound effect\nvolume"), 284 + 40 + LXOFFSET (), 80); + DrawTextCenter (gettext ("Music\nvolume"), 399 + 40 + LXOFFSET (), 80); + DrawTextCenter (gettext ("Video\nsequences"), 514 + 40 + LXOFFSET (), 80); + + snprintf (res, sizeof (res), "x%d", m_speed); + lg = GetTextWidth (res); + lg = IsRightReading () ? -lg : lg; + pos.x = (54 + 40) - lg / 2 + LXOFFSET (); + pos.y = 330 - 20; + DrawText (m_pPixmap, pos, res); + + snprintf (res, sizeof (res), "%d", m_pSound->GetAudioVolume ()); + lg = GetTextWidth (res); + lg = IsRightReading () ? -lg : lg; + pos.x = (284 + 40) - lg / 2 + LXOFFSET (); + pos.y = 330 - 20; + DrawText (m_pPixmap, pos, res); + + snprintf (res, sizeof (res), "%d", m_pSound->GetMidiVolume ()); + lg = GetTextWidth (res); + lg = IsRightReading () ? -lg : lg; + pos.x = (399 + 40) - lg / 2 + LXOFFSET (); + pos.y = 330 - 20; + DrawText (m_pPixmap, pos, res); + + char * text = gettext ("No"); + if (m_pMovie->GetEnable () && m_bMovie) + text = gettext ("Yes"); + lg = GetTextWidth (text); + lg = IsRightReading () ? -lg : lg; + pos.x = (514 + 40) - lg / 2 + LXOFFSET (); + pos.y = 330 - 20; + DrawText (m_pPixmap, pos, text); + + if (!m_scrollSpeed) + snprintf (res, sizeof (res), "%s", gettext ("None")); + else + snprintf (res, sizeof (res), "%d", m_scrollSpeed); + lg = GetTextWidth (res); + lg = IsRightReading () ? -lg : lg; + pos.x = (169 + 40) - lg / 2 + LXOFFSET (); + pos.y = 330 - 20; + DrawText (m_pPixmap, pos, res); + } + + // Draw the settings + if (m_phase == EV_PHASE_SETTINGS) + { + DrawTextCenter ( + gettext ("Interface language\nand sounds"), 54 + 40 + LXOFFSET (), 80); + DrawTextCenter ( + gettext ("Select the\nwindow mode"), 169 + 40 + LXOFFSET (), 80); + DrawTextCenter ( + g_bFullScreen ? gettext ("Change the\ndisplay mode") + : gettext ("Change the\nwindow size"), + 284 + 40 + LXOFFSET (), 80); + DrawTextCenter ( + gettext ("Choose the\nmusic format"), 399 + 40 + LXOFFSET (), 80); + DrawTextCenter ( + gettext ("Change the\nrender quality"), 514 + 40 + LXOFFSET (), 80); + + const auto locale = GetLocale (); + std::string lang; + if (locale == "en") + lang = "English"; + else if (locale == "en_US") + lang = "American english"; + else if (locale == "fr") + lang = "Français"; + else if (locale == "de") + lang = "Deutsch"; + else if (locale == "it") + lang = "Italiano"; + else if (locale == "pl") + lang = "Polski"; + else if (locale == "tr") + lang = "Türkçe"; + else if (locale == "pt") + lang = "Português"; + else if (locale == "he") + lang = "עברית"; + + lg = GetTextWidth (lang.c_str ()); + lg = IsRightReading () ? -lg : lg; + pos.x = (54 + 40) - lg / 2 + LXOFFSET (); + pos.y = 330 - 20; + DrawText (m_pPixmap, pos, lang.c_str ()); + + const char * text = + g_bFullScreen ? gettext ("Fullscreen") : gettext ("Windowed"); + lg = GetTextWidth (text); + lg = IsRightReading () ? -lg : lg; + pos.x = (169 + 40) - lg / 2 + LXOFFSET (); + pos.y = 330 - 20; + DrawText (m_pPixmap, pos, text); + + if (!g_bFullScreen) + snprintf (res, sizeof (res), "%dx", g_zoom); + else + snprintf ( + res, sizeof (res), "%s", + g_zoom == 2 ? gettext ("Legacy") : gettext ("Desktop")); + + lg = GetTextWidth (res); + lg = IsRightReading () ? -lg : lg; + pos.x = (284 + 40) - lg / 2 + LXOFFSET (); + pos.y = 330 - 20; + DrawText (m_pPixmap, pos, res); + + text = (g_restoreMidi && mid) || !ogg ? gettext ("Midi") : gettext ("Ogg"); + lg = GetTextWidth (text); + lg = IsRightReading () ? -lg : lg; + pos.x = (399 + 40) - lg / 2 + LXOFFSET (); + pos.y = 330 - 20; + DrawText (m_pPixmap, pos, text); + + text = + g_bFullScreen && g_zoom == 1 + ? (g_renderQuality ? gettext ("Anti-aliasing") : gettext ("Aliasing")) + : gettext ("Not available"); + lg = GetTextWidth (text); + lg = IsRightReading () ? -lg : lg; + pos.x = (514 + 40) - lg / 2 + LXOFFSET (); + pos.y = 330 - 20; + DrawText (m_pPixmap, pos, text); + } + + // Show the ending text + if (m_phase == EV_PHASE_BYE) + { + char * text; + + text = gettext ("You have played Planet Blupi."); + lg = GetTextWidth (text); + lg = IsRightReading () ? -lg : lg; + pos.x = LXIMAGE () / 2 - lg / 2; + pos.y = 20; + DrawText (m_pPixmap, pos, text); + + text = gettext ("We hope you have had as much fun playing the game as we " + "had making it !"); + lg = GetTextWidth (text); + lg = IsRightReading () ? -lg : lg; + pos.x = LXIMAGE () / 2 - lg / 2; + pos.y = 40; + DrawText (m_pPixmap, pos, text); + + static const std::string libs[] = { + gettext ( + "This game uses statically linked free and open-source libraries:"), + gettext (" - argagg (MIT)"), + gettext (" - FFmpeg (LGPLv2.1)"), + gettext (" - GNU/gettext and GNU/libiconv (GPLv3)"), + gettext (" - libasound (LGPLv2.1)"), + gettext (" - libcurl (MIT/X derivate)"), + gettext (" - libogg and libvorbis (own license)"), + gettext (" - libpng (own license)"), + gettext (" - libpulse (LGPLv2.1)"), + gettext (" - libsndfile (LGPLv3)"), + gettext (" - SDL_kitchensink (MIT)"), + gettext (" - SDL2, SDL2_image and SDL2_mixer (zlib license)"), + gettext (" - zlib (own license)"), + gettext ( + "All licenses are available under share/doc/planetblupi/copyright")}; + + for (size_t i = 0; i < countof (libs); ++i) + { + pos.x = 30 + LXOFFSET (); + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x; + pos.y = 120 + i * 20; + DrawText (m_pPixmap, pos, libs[i].c_str ()); + } + + text = gettext ("This game is an original creation of Epsitec SA, CH-1400 " + "Yverdon-les-Bains"); + lg = GetTextWidth (text); + lg = IsRightReading () ? -lg : lg; + pos.x = LXIMAGE () / 2 - lg / 2; + pos.y = 430; + DrawText (m_pPixmap, pos, text); + + text = gettext ("http://www.blupi.org info@blupi.org"); + lg = GetTextWidth (text); + lg = IsRightReading () ? -lg : lg; + pos.x = LXIMAGE () / 2 - lg / 2; + pos.y = 450; + DrawText (m_pPixmap, pos, text); + } + + // Show the text when the CD-Rom must be inserted (deprecated). + if (m_phase == EV_PHASE_INSERT) + DrawTextCenter ( + gettext ("Insert CD-Rom Planet Blupi and wait a few seconds..."), + LXIMAGE () / 2, 20); + + if (m_phase == EV_PHASE_BUILD) + SetEnable (EV_PHASE_UNDO, m_pDecor->IsUndo ()); + + // Draw the tooltips. + if (m_textToolTips[0] != 0) + DrawText (m_pPixmap, m_posToolTips, m_textToolTips); + + return true; +} + +/** + * \brief Return the mouse sprite to use for a position. + * + * \param[in] pos - The position. + * \return the sprite. + */ +MouseSprites +CEvent::MousePosToSprite (Point pos) +{ + MouseSprites sprite; + bool bUp = false, bDown = false, bLeft = false, bRight = false; + + sprite = SPRITE_POINTER; + + if (m_phase == EV_PHASE_PLAY || m_phase == EV_PHASE_BUILD) + { + if ( + pos.x >= POSMAPX && pos.x <= POSMAPX + DIMMAPX && pos.y >= POSMAPY && + pos.y <= POSMAPY + DIMMAPY) + sprite = SPRITE_MAP; + + if (g_bFullScreen && !m_bDemoRec && !m_bDemoPlay && m_scrollSpeed != 0) + { + if (pos.x <= 5 && pos.x >= -2) + bLeft = true; + + if (pos.x >= LXIMAGE () - 5 && pos.x <= LXIMAGE () + 2) + bRight = true; + + if (pos.y <= 5 && pos.y >= -2) + bUp = true; + + if (pos.y >= LYIMAGE () - 5 && pos.y <= LYIMAGE () + 2) + bDown = true; + + if (bLeft) + sprite = SPRITE_ARROWL; + if (bRight) + sprite = SPRITE_ARROWR; + if (bUp) + sprite = SPRITE_ARROWU; + if (bDown) + sprite = SPRITE_ARROWD; + if (bLeft && bUp) + sprite = SPRITE_ARROWUL; + if (bLeft && bDown) + sprite = SPRITE_ARROWDL; + if (bRight && bUp) + sprite = SPRITE_ARROWUR; + if (bRight && bDown) + sprite = SPRITE_ARROWDR; + } + + if (this->statDisabled) + sprite = SPRITE_ARROW; + } + else if (m_phase == EV_PHASE_INTRO1) + sprite = SPRITE_POINTER; + else if (m_phase == EV_PHASE_BYE) + sprite = SPRITE_POINTER; + else + { + if (!MouseOnButton (pos)) + sprite = SPRITE_ARROW; + } + + if ( + m_bFillMouse && // bidon présent ? + pos.x >= POSDRAWX && pos.x <= POSDRAWX + DIMDRAWX && pos.y >= POSDRAWY && + pos.y <= POSDRAWY + DIMDRAWY) + sprite = SPRITE_FILL; + if (m_bWaitMouse) // sablier présent ? + sprite = SPRITE_WAIT; + if (m_bHideMouse) // souris cachée ? + sprite = SPRITE_EMPTY; + + return sprite; +} + +/** + * \brief Main mouse sprite handling. + * + * \param[in] pos - The position. + */ +void +CEvent::MouseSprite (Point pos) +{ + m_mouseSprite = MousePosToSprite (pos); + m_pPixmap->ChangeSprite (m_mouseSprite); +} + +/** + * \brief Set or remove the waiting mouse sprite. + * + * \param[in] bWait - If waiting. + */ +void +CEvent::WaitMouse (bool bWait) +{ + m_bWaitMouse = bWait; + + if (bWait) + m_mouseSprite = SPRITE_WAIT; + else + m_mouseSprite = MousePosToSprite (GetMousePos ()); + m_pPixmap->SetMouseSprite (m_mouseSprite); + m_pPixmap->ChangeSprite (m_mouseSprite); +} + +/** + * \brief Hide or show the mouse. + * + * \param[in] bHide - If hide. + */ +void +CEvent::HideMouse (bool bHide) +{ + m_bHideMouse = bHide; + + if (bHide) + { + m_mouseSprite = SPRITE_EMPTY; + SDL_ShowCursor (SDL_FALSE); + } + else + { + m_mouseSprite = MousePosToSprite (GetMousePos ()); + SDL_ShowCursor (SDL_TRUE); + } + + m_pPixmap->SetMouseSprite (m_mouseSprite); + m_pPixmap->ChangeSprite (m_mouseSprite); +} + +/** + * \brief Handle events for buttons. + * + * \param[in] event - The SDL event. + * \param[in] pos - The position. + * \return true if the event is handled. + */ +bool +CEvent::EventButtons (const SDL_Event & event, Point pos) +{ + Sint32 lg; + Point _pos = pos; + + // Cherche le tool tips à utiliser pour la souris. + m_textToolTips[0] = 0; + m_posToolTips.x = -1; + + if (IsRightReading ()) + _pos.x = LXIMAGE () - _pos.x; + + if (m_phase == EV_PHASE_PLAY) + { + auto progress = [&](CJauge & prog, const char * text) -> bool { + if (prog.GetHide ()) + return false; + + Point test = prog.GetPos (); + if ( + pos.x >= test.x && pos.x <= test.x + DIMJAUGEX && pos.y >= test.y && + pos.y <= test.y + DIMJAUGEY) + { + snprintf (m_textToolTips, sizeof (m_textToolTips), "%s", text); + lg = GetTextWidth (m_textToolTips); + lg = IsRightReading () ? -lg : lg; + test.x += (DIMJAUGEX - lg) / 2; + test.y += 4; + m_posToolTips = test; + return true; + } + return false; + }; + + const auto spotted = progress (m_jauges[0], gettext ("Blupi's energy")); + if (!spotted) + progress (m_jauges[1], gettext ("Work done")); + } + else + { + int i = 0; + + assert (m_index >= 0); + + while (table[m_index].buttons[i].message != 0) + { + const auto text = m_buttons[i].GetToolTips (pos); + if (text) + { + snprintf (m_textToolTips, sizeof (m_textToolTips), "%s", text); + lg = GetTextWidth (m_textToolTips); + pos.x += IsRightReading () ? 0 : 10; + pos.y += 20; + if (pos.x > LXIMAGE () + (IsRightReading () ? 0 : -lg)) + pos.x = LXIMAGE () - lg; + if (pos.x < 0) + pos.x = 0; + if (pos.y > LYIMAGE () - 14) + pos.y = LYIMAGE () - 14; + m_posToolTips = pos; + break; + } + i++; + } + } + + if (m_phase == EV_PHASE_PLAY) + { + m_bHiliInfoButton = false; + if ( + pos.x > m_posInfoButton.x + 6 && + pos.x < m_posInfoButton.x + DIMBUTTONX - 6 && + pos.y > m_posInfoButton.y + 8 && + pos.y < m_posInfoButton.y + DIMBUTTONY - 8) + { + m_bHiliInfoButton = true; + + if ( + event.type == SDL_MOUSEBUTTONUP && + (event.button.button == SDL_BUTTON_LEFT || + event.button.button == SDL_BUTTON_RIGHT)) + { + m_pSound->PlayImage ( + m_pDecor->GetInfoMode () ? SOUND_CLOSE : SOUND_OPEN, pos); + + // Show or hide the informations at the top. + m_pDecor->SetInfoMode (!m_pDecor->GetInfoMode ()); + } + } + + m_bHiliHelpButton = false; + if ( + m_posHelpButton.x != -1 && pos.x > m_posHelpButton.x && + pos.x < m_posHelpButton.x + DIMBUTTONX && pos.y > m_posHelpButton.y && + pos.y < m_posHelpButton.y + DIMBUTTONY) + { + m_bHiliHelpButton = true; + + if ( + event.type == SDL_MOUSEBUTTONDOWN && + (event.button.button == SDL_BUTTON_LEFT || + event.button.button == SDL_BUTTON_RIGHT)) + m_pSound->PlayImage (SOUND_CLICK, pos); + if ( + event.type == SDL_MOUSEBUTTONUP && + (event.button.button == SDL_BUTTON_LEFT || + event.button.button == SDL_BUTTON_RIGHT)) + { + // Reverse the help mode in the informations. + m_bInfoHelp = !m_bInfoHelp; + + if (m_bInfoHelp) + ReadLibelle (GetWorld (), false, true); + else + ReadLibelle (GetWorld () + 2, false, false); + } + } + } + + if (m_phase == EV_PHASE_BUILD) + { + if ( + event.type == SDL_MOUSEBUTTONDOWN && + (event.button.button == SDL_BUTTON_LEFT || + event.button.button == SDL_BUTTON_RIGHT)) + { + m_pDecor->HideTooltips (true); // Remove tooltips for the decor. + } + if ( + event.type == SDL_MOUSEBUTTONUP && + (event.button.button == SDL_BUTTON_LEFT || + event.button.button == SDL_BUTTON_RIGHT)) + m_pDecor->HideTooltips (false); + } + + int i = 0; + + assert (m_index >= 0); + + while (table[m_index].buttons[i].message != 0) + { + if (m_buttons[i].TreatEvent (event)) + return true; + i++; + } + + if (m_phase == EV_PHASE_PLAY) + { + if (m_menu.TreatEvent (event)) + return true; + } + + return false; +} + +/** + * \brief Notify if the mouse is on a button. + * + * \param[in] pos - The mouse position. + * \return true if the mouse is on a button. + */ +bool +CEvent::MouseOnButton (Point pos) +{ + Sint32 i; + + if (m_index < 0) + return false; + + i = 0; + while (table[m_index].buttons[i].message != 0) + { + if (m_buttons[i].MouseOnButton (pos)) + return true; + i++; + } + + return false; +} + +/** + * \brief Return the table index for a specific phase. + * + * \param[in] phase - The phase. + * \return the index in `table`. + */ +Sint32 +CEvent::SearchPhase (Uint32 phase) +{ + Sint32 i = 0; + + while (table[i].phase != 0) + { + if (table[i].phase == phase) + return i; + i++; + } + + return -1; +} + +/** + * \brief Return the world number. + * + * \return the number. + */ +Sint32 +CEvent::GetWorld () +{ + if (m_bPrivate) + return m_private; + if (m_bSchool) + return m_exercice; + else + return m_mission; +} + +/** + * \brief Return the physical world number. + * + * This number should be the same as the filename. + * + * \return the number. + */ +Sint32 +CEvent::GetPhysicalWorld () +{ + if (m_bPrivate) + return m_private + 200; + if (m_bSchool) + return m_exercice; + else + return m_mission + 100; +} + +Sint32 +CEvent::GetImageWorld () +{ + if (m_bPrivate) + return 2; + if (m_bSchool) + return 0; + else + return 1; +} + +/** + * Notify if the help is available. + * + * \return true if available. + */ +bool +CEvent::IsHelpHide () +{ + bool bHide = true; + + if (m_bHelp || m_pDecor->GetTotalTime () > DEF_TIME_HELP) + bHide = false; + if (m_bSchool || m_bPrivate) + { + bHide = true; // No help for the exercises. + } + + return bHide; +} + +bool +CEvent::IsBaseMusicAvailable (Sint32 music, const std::string & format) +{ + std::string absolute; + auto filename = + string_format ("music/music%.3d.%s", music - 1, format.c_str ()); + return FileExists (filename, absolute, LOCATION_BASE); +} + +std::string +CEvent::GetMusicLocation (Sint32 music) +{ + static const std::string exts[] = {"ogg", "mid"}; + static const Location locs[] = {LOCATION_USER, LOCATION_BASE}; + std::string absolute; + + // Look for music in the user directory, then in the game directory. + for (size_t i = 0; i < countof (locs); ++i) + { + auto filename = string_format ( + "music/music%.3d.%s", music - 1, exts[g_restoreMidi ? 1 : 0].c_str ()); + if (!FileExists (filename, absolute, locs[i])) + filename = string_format ( + "music/music%.3d.%s", music - 1, exts[g_restoreMidi ? 0 : 1].c_str ()); + + if (FileExists (filename, absolute, locs[i])) + break; + + absolute = ""; + } + + return absolute; +} + +bool +CEvent::LoadBackground () +{ + Point totalDim, iconDim; + std::string filename; + auto backWideName = table[m_index].backWideName; + + filename = table[m_index].backName; + if (filename.find ("%.3d") != std::string::npos) + { + auto id = GetImageWorld (); + filename = string_format (table[m_index].backName, id); + + if (table[m_index].phase == EV_PHASE_LASTWIN) + { + switch (id) + { + case 0: + backWideName = "back-disco.png"; + break; + case 1: + backWideName = "back-stars.png"; + break; + case 2: + backWideName = "back-win.png"; + break; + } + } + } + + totalDim.x = LXLOGIC (); + totalDim.y = LYLOGIC (); + iconDim.x = 0; + iconDim.y = 0; + return m_pPixmap->Cache ( + CHBACK, filename, totalDim, iconDim, table[m_index].mode, backWideName); +} + +/** + * \brief Change the phase. + * + * \param[in] phase - The new phase. + * \return true if the phase has changed. + */ +bool +CEvent::ChangePhase (Uint32 phase) +{ + Sint32 index, world, time, total, music, i, max; + char * pButtonExist; + bool bEnable, bHide; + Term * pTerm; + + if ( + phase != EV_PHASE_SETUPp && phase != EV_PHASE_WRITEp && + phase != EV_PHASE_PLAY) + m_pSound->StopMusic (); + if (phase == EV_PHASE_SETUPp && m_bPause) + m_pSound->StopMusic (); + + m_textToolTips[0] = 0; + m_posToolTips.x = -1; + m_bPause = false; + m_keymod = 0; + m_bMouseDown = false; + m_debugPos.x = 0; + m_debugPos.y = 0; + + m_pDecor->SetInfoMode (false); + m_bInfoHelp = false; + m_bHiliInfoButton = false; + m_bHiliHelpButton = false; + + if (phase == EV_PHASE_INTRO1) + m_introTime = 0; + + if (phase == EV_PHASE_INIT) + m_demoTime = 0; + + if (phase != EV_PHASE_PLAY) + DemoRecStop (); // stop recording + + m_pDecor->UndoClose (); // libère le buffer undo + + index = SearchPhase (phase); + if (index < 0) + return false; + + HideMouse (false); // montre la souris + WaitMouse (true); // met le sablier + + if (m_bBuildModify) + { + m_pDecor->InitAfterBuild (); + m_bBuildModify = false; + } + + if (m_phase == EV_PHASE_BUILD && phase == EV_PHASE_INFO) // quitte + // construction ? + { + m_pDecor->Write ( + GetPhysicalWorld (), false, GetPhysicalWorld (), 0, 0); // écrit le monde + } + + // FIXME: pause is better if the game is not stop but just interrupted + if (m_phase == EV_PHASE_PLAY && m_phase != phase) + { + static const std::set except = {SOUND_WIN, SOUND_LOST}; + m_pSound->StopAllSounds (false, &except); + } + + m_phase = phase; // change phase + m_index = index; + + if (!this->LoadBackground ()) + { + WaitMouse (false); + m_tryInsertCount = 40; + m_tryPhase = m_phase; + return ChangePhase (EV_PHASE_INSERT); // insert the CD-Rom ... + } + + if ( + m_phase == EV_PHASE_READ || m_phase == EV_PHASE_WRITE || + m_phase == EV_PHASE_WRITEp) + { + for (i = 0; i < 10; i++) + { + if (m_pDecor->FileExist (i, true, world, time, total)) + { + m_fileWorld[i] = world; + m_fileTime[i] = time; + } + else + m_fileWorld[i] = -1; + } + } + + if ( + m_phase == EV_PHASE_INFO || m_phase == EV_PHASE_HISTORY0 || + m_phase == EV_PHASE_HISTORY1) + { + if ( + !m_pDecor->Read ( + GetPhysicalWorld (), false, world, time, total) && // read the world + !m_bAccessBuild && + !m_bPrivate) + { + m_tryInsertCount = 40; + m_tryPhase = m_phase; + return ChangePhase (EV_PHASE_INSERT); // insert the CD-Rom ... + } + m_pDecor->SetTime (0); + m_pDecor->SetTotalTime (0); + m_pDecor->SetInvincible (false); + m_pDecor->SetSuper (false); + } + + if ( + m_phase == EV_PHASE_INFO || m_phase == EV_PHASE_STOP || + m_phase == EV_PHASE_HELP || m_phase == EV_PHASE_HISTORY0 || + m_phase == EV_PHASE_HISTORY1) + { + if (m_bPrivate) + PrivateLibelle (); + else if (m_phase == EV_PHASE_INFO || m_phase == EV_PHASE_STOP) + { + if (m_bSchool) + ReadLibelle (GetWorld (), m_bSchool, false); + else + ReadLibelle (GetWorld () + 2, m_bSchool, false); + } + else if (m_phase == EV_PHASE_HELP) + ReadLibelle (GetWorld (), false, true); + else + { + if (m_phase == EV_PHASE_HISTORY0) + world = 0; + else + world = 1; + ReadLibelle (world, false, false); + } + } + + if (m_phase == EV_PHASE_TESTCD) + { + if (m_pDecor->Read (0, false, world, time, total)) // read the world + { + return ChangePhase (EV_PHASE_INIT); // ok + } + else + { + m_tryInsertCount = 40; + m_tryPhase = m_phase; + return ChangePhase (EV_PHASE_INSERT); // insert the CD-Rom ... + } + } + + m_jauges[0].SetHide (true); + m_jauges[1].SetHide (true); + CreateButtons (phase); // create the buttons accordingly to the phase + m_bMenu = false; + m_pDecor->HideTooltips (false); + m_menu.Delete (); + m_pDecor->BlupiSetArrow (0, false); // remove all arrows + m_pDecor->ResetHili (); // remove all highlights + + if (m_phase == EV_PHASE_PLAY) + { + m_pDecor->LoadImages (); + m_pDecor->SetBuild (false); + m_pDecor->EnableFog (true); + m_pDecor->NextPhase (0); // rebuild the map immediatly + m_pDecor->StatisticInit (); + m_pDecor->TerminatedInit (); + } + + if (m_phase == EV_PHASE_BUILD) + { + m_bBuildModify = true; + SetState (EV_DECOR1, 1); + SetMenu (EV_DECOR1, 0); // grass + SetMenu (EV_DECOR2, 2); // tree + SetMenu (EV_DECOR3, 1); // house + SetMenu (EV_DECOR4, 2); // strong blupi + SetMenu (EV_DECOR5, 1); // fire + m_pDecor->LoadImages (); + m_pDecor->SetBuild (true); + m_pDecor->EnableFog (false); + m_pDecor->BlupiDeselect (); + m_pDecor->NextPhase (0); // rebuild the map immediatly + } + + if (m_phase == EV_PHASE_INFO) + { + bEnable = true; + if (GetWorld () == 0) + bEnable = false; + SetEnable (EV_PREV, bEnable); + + bEnable = true; + if (m_bAllMissions) + max = 99; + else + max = m_maxMission; + if (!m_bSchool && GetWorld () >= max) + bEnable = false; + if (!m_pDecor->FileExist ( + GetPhysicalWorld () + 1, false, world, time, total)) + bEnable = false; + + if (m_bAccessBuild || m_pDecor->GetTotalTime () > DEF_TIME_HELP * 6) + bEnable = true; + + if (GetWorld () >= 99) + bEnable = false; + + if (m_bPrivate) + bEnable = GetWorld () < 20 - 1; + SetEnable (EV_NEXT, bEnable); + + bHide = true; + if (m_bAccessBuild || m_bPrivate) + bHide = false; + SetHide (EV_PHASE_BUILD, bHide); + + if (m_bSchool) + { + SetHide (EV_PHASE_SKILL1, true); + SetHide (EV_PHASE_SKILL2, true); + } + else + { + SetState (EV_PHASE_SKILL1, m_pDecor->GetSkill () == 0 ? 1 : 0); + SetState (EV_PHASE_SKILL2, m_pDecor->GetSkill () == 1 ? 1 : 0); + } + } + + if (m_phase == EV_PHASE_STOP) + SetHide (EV_PHASE_HELP, IsHelpHide ()); + + if (m_phase == EV_PHASE_READ) + { + for (i = 0; i < 10; i++) + { + if (m_fileWorld[i] == -1) + SetEnable (EV_READ0 + i, false); + } + } + + if (m_phase == EV_PHASE_BUTTON) + { + pButtonExist = m_pDecor->GetButtonExist (); + + for (i = 0; i < MAXBUTTON; i++) + SetState (EV_BUTTON0 + i, pButtonExist[i]); + } + + if (m_phase == EV_PHASE_TERM) + { + pTerm = m_pDecor->GetTerminated (); + + SetState (EV_BUTTON1, pTerm->bHachBlupi ? 1 : 0); + SetState (EV_BUTTON2, pTerm->bHachPlanche ? 1 : 0); + SetState (EV_BUTTON3, pTerm->bStopFire ? 1 : 0); + SetState (EV_BUTTON8, pTerm->bHomeBlupi ? 1 : 0); + SetState (EV_BUTTON9, pTerm->bKillRobots ? 1 : 0); + SetState (EV_BUTTON10, pTerm->bHachTomate ? 1 : 0); + SetState (EV_BUTTON11, pTerm->bHachMetal ? 1 : 0); + SetState (EV_BUTTON12, pTerm->bHachRobot ? 1 : 0); + } + + if (m_phase == EV_PHASE_MUSIC) + { + music = m_pDecor->GetMusic (); + + for (i = 0; i < 11; i++) + SetState (EV_BUTTON1 + i, music == i ? 1 : 0); + } + + if (m_phase == EV_PHASE_REGION) + { + music = m_pDecor->GetRegion (); + + for (i = 0; i < 4; i++) + SetState (EV_BUTTON1 + i, music == i ? 1 : 0); + } + + if (m_phase == EV_PHASE_PLAY || m_phase == EV_PHASE_MUSIC) + { + if (m_pSound->IsPlayingMusic ()) + { + m_pSound->AdaptVolumeMusic (); + } + else + { + music = m_pDecor->GetMusic (); + if (music > 0) + { + auto absolute = this->GetMusicLocation (music); + + m_pSound->StopMusic (); + m_pSound->PlayMusic (absolute); + } + } + } + + if (phase == EV_PHASE_H0MOVIE) + { + m_movieToStart = "movie/history0.mkv"; + m_phaseAfterMovie = EV_PHASE_HISTORY0; + } + + if (phase == EV_PHASE_H1MOVIE) + { + m_movieToStart = "movie/history1.mkv"; + m_phaseAfterMovie = EV_PHASE_HISTORY1; + } + + if (phase == EV_PHASE_H2MOVIE) + { + m_movieToStart = "movie/history2.mkv"; + m_phaseAfterMovie = EV_PHASE_INFO; + } + + if (phase == EV_PHASE_PLAYMOVIE) + { + m_movieToStart = string_format ("movie/play%.3d.mkv", GetPhysicalWorld ()); + m_phaseAfterMovie = EV_PHASE_PLAY; + } + + if (phase == EV_PHASE_WINMOVIE) + { + m_movieToStart = string_format ("movie/win%.3d.mkv", GetPhysicalWorld ()); + m_phaseAfterMovie = EV_PHASE_WIN; + + if ( + (m_bPrivate && GetPhysicalWorld () - 200 == MAX_PRIVATE_MISSIONS - 1) || + (!m_bPrivate && + m_pDecor->FileExist (GetPhysicalWorld (), false, world, time, total) && + !m_pDecor->FileExist ( + GetPhysicalWorld () + 1, false, world, time, total))) + m_phaseAfterMovie = EV_PHASE_LASTWIN; + } + + WaitMouse (false); + return true; +} + +/** + * \brief Return the current phase. + * + * \return the phase number. + */ +Uint32 +CEvent::GetPhase () +{ + return m_phase; +} + +/** + * \brief Try to read the CD-Rom. + */ +void +CEvent::TryInsert () +{ + if (m_tryInsertCount == 0) + ChangePhase (m_tryPhase); + else + m_tryInsertCount--; +} + +/** + * \brief Start a movie if necessary. + * + * \return true if the movie has started. + */ +bool +CEvent::MovieToStart () +{ + bool movie = false; + + if (m_movieToStart[0] != 0) // is movie available? + { + if (StartMovie (m_movieToStart)) + { + movie = true; + m_phase = m_phaseAfterMovie; // the next normal phase + } + else + ChangePhase (m_phaseAfterMovie); + + m_movieToStart[0] = 0; + } + + return movie; +} + +/** + * \brief Shift the decor. + * + * \param[in] dx - Delta x. + * \param[in] dy - Delta y. + */ +void +CEvent::DecorShift (Sint32 dx, Sint32 dy) +{ + Point corner; + + if (m_phase != EV_PHASE_PLAY && m_phase != EV_PHASE_BUILD) + return; + + corner = m_pDecor->GetCorner (); + + corner.x += dx; + corner.y += dy; + + m_pDecor->SetCorner (corner); +} + +/** + * \brief Shift the decor when the mouse is on the sides. + */ +void +CEvent::DecorAutoShift () +{ + Sint32 max, maxLimit = 4, xMoveFactor = 1, yMoveFactor = 1, vectorFactor = 1; + Point offset; + Uint32 dir = 0; + + bool byKeyboard = !!this->shiftDirection; + + if (byKeyboard) + { + dir = this->shiftDirection; + xMoveFactor = 2; + yMoveFactor = 3; + vectorFactor = 2; + if (m_scrollSpeed == 1) + maxLimit = 5; // 4..2..1 + } + else + { + if (m_bDemoRec || m_bDemoPlay) + return; + + switch (m_mouseSprite) + { + case SPRITE_ARROWL: + dir = DIRECTION_LEFT; + break; + + case SPRITE_ARROWR: + dir = DIRECTION_RIGHT; + break; + + case SPRITE_ARROWU: + dir = DIRECTION_UP; + break; + + case SPRITE_ARROWD: + dir = DIRECTION_DOWN; + break; + + case SPRITE_ARROWUL: + dir = DIRECTION_UP | DIRECTION_LEFT; + break; + + case SPRITE_ARROWUR: + dir = DIRECTION_UP | DIRECTION_RIGHT; + break; + + case SPRITE_ARROWDL: + dir = DIRECTION_DOWN | DIRECTION_LEFT; + break; + + case SPRITE_ARROWDR: + dir = DIRECTION_DOWN | DIRECTION_RIGHT; + break; + + default: + break; + } + } + + m_bShift = false; + + if (!byKeyboard && (!g_bFullScreen || m_scrollSpeed == 0)) + return; + + max = maxLimit - m_scrollSpeed; // max <- 3..1 + + if (m_phase == EV_PHASE_PLAY || m_phase == EV_PHASE_BUILD) + { + if (m_shiftPhase == 0) // start shift ? + { + switch (dir) + { + case DIRECTION_LEFT: + m_shiftOffset.x = +2; + m_shiftOffset.y = 0; + m_shiftVector.x = -1; + m_shiftVector.y = +1; + break; + + case DIRECTION_RIGHT: + m_shiftOffset.x = -2; + m_shiftOffset.y = 0; + m_shiftVector.x = +1; + m_shiftVector.y = -1; + break; + + case DIRECTION_UP: + m_shiftOffset.x = 0; + m_shiftOffset.y = +2; + m_shiftVector.x = -1; + m_shiftVector.y = -1; + if (vectorFactor > 1) + ++vectorFactor; + break; + + case DIRECTION_DOWN: + m_shiftOffset.x = 0; + m_shiftOffset.y = -2; + m_shiftVector.x = +1; + m_shiftVector.y = +1; + if (vectorFactor > 1) + ++vectorFactor; + break; + + default: + if (dir == (DIRECTION_UP | DIRECTION_LEFT)) + { + m_shiftOffset.x = +1; + m_shiftOffset.y = +1; + m_shiftVector.x = -1; + m_shiftVector.y = 0; + if (vectorFactor > 1) + ++vectorFactor; + } + else if (dir == (DIRECTION_UP | DIRECTION_RIGHT)) + { + m_shiftOffset.x = -1; + m_shiftOffset.y = +1; + m_shiftVector.x = 0; + m_shiftVector.y = -1; + if (vectorFactor > 1) + ++vectorFactor; + } + else if (dir == (DIRECTION_DOWN | DIRECTION_LEFT)) + { + m_shiftOffset.x = +1; + m_shiftOffset.y = -1; + m_shiftVector.x = 0; + m_shiftVector.y = +1; + if (vectorFactor > 1) + ++vectorFactor; + } + else if (dir == (DIRECTION_DOWN | DIRECTION_RIGHT)) + { + m_shiftOffset.x = -1; + m_shiftOffset.y = -1; + m_shiftVector.x = +1; + m_shiftVector.y = 0; + if (vectorFactor > 1) + ++vectorFactor; + } + else + { + m_shiftOffset.x = 0; + m_shiftOffset.y = 0; + m_shiftVector.x = 0; + m_shiftVector.y = 0; + } + break; + } + + m_shiftOffset.x *= xMoveFactor; + m_shiftOffset.y *= yMoveFactor; + m_shiftVector.x *= vectorFactor; + m_shiftVector.y *= vectorFactor; + + if (m_shiftVector.x != 0 || m_shiftVector.y != 0) + m_shiftPhase = max; + } + + if (m_shiftPhase > 0) + { + m_bShift = true; + m_shiftPhase--; + + offset.x = m_shiftOffset.x * (max - m_shiftPhase) * (DIMCELX / 2 / max); + offset.y = m_shiftOffset.y * (max - m_shiftPhase) * (DIMCELY / 2 / max); + m_pDecor->SetShiftOffset (offset); + + if (m_shiftPhase == 0) // last phase ? + { + this->shiftDirection = 0; + offset.x = 0; + offset.y = 0; + m_pDecor->SetShiftOffset (offset); + DecorShift (m_shiftVector.x, m_shiftVector.y); + } + } + } +} + +/** + * \brief Notify if a shift is doing. + * + * \return true of the shift is doing. + */ +bool +CEvent::IsShift () +{ + return m_bShift; +} + +// Modifie le décor lorsque le bouton de la souris est pressé. + +bool +CEvent::PlayDown (Point pos, const SDL_Event & event) +{ + bool bDecor = false; + bool bMap = false; + Sint32 rank, h; + Buttons button; + Point cel; + + m_pDecor->BlupiSetArrow (0, false); // enlève toutes les flèches + + m_bMouseDown = false; + + if (m_bMenu) + { + m_menu.Message (); + m_bMenu = false; + m_pDecor->HideTooltips (false); + m_menu.Delete (); + return true; + } + + m_pDecor->StatisticDown (pos); + + if ( + pos.x >= POSMAPX && pos.x <= POSMAPX + DIMMAPX && pos.y >= POSMAPY && + pos.y <= POSMAPY + DIMMAPY) + bMap = true; + h = m_pDecor->GetInfoHeight () + POSDRAWY; + if ( + pos.x >= POSDRAWX && pos.x <= POSDRAWX + DIMDRAWX && pos.y >= h && + pos.y <= h + DIMDRAWY) + bDecor = true; + + if (!bDecor && !bMap) + return false; + + cel = m_pDecor->ConvPosToCel (pos, true); + if (event.button.button == SDL_BUTTON_RIGHT) + { + if (bMap) + button = BUTTON_GO; + else + button = m_pDecor->GetDefButton (cel); + m_pDecor->BlupiGoal (cel, button); + return true; + } + + if (bMap) + { + m_pDecor->SetCorner (cel, true); + m_pDecor->NextPhase (0); // faudra refaire la carte tout de suite + return true; + } + + rank = m_pDecor->GetTargetBlupi (pos); + if (rank >= 0 && !m_pDecor->IsWorkBlupi (rank)) + { + m_bHili = true; + m_bMouseDown = true; + m_pDecor->BlupiHiliDown (pos, !!(m_keymod & KMOD_SHIFT)); + } + else + { + m_bHili = false; + m_bMouseDown = true; + } + + return true; +} + +// Modifie le décor lorsque la souris est déplacée. + +bool +CEvent::PlayMove (Point pos) +{ + if (m_bMenu) + { + if (!m_menu.IsExist ()) + { + m_bMenu = false; + m_pDecor->HideTooltips (false); + m_menu.Delete (); + } + return true; + } + + m_pDecor->StatisticMove (pos, this->statDisabled); + + if (m_bMouseDown) // bouton souris pressé ? + { + if (m_bHili) + m_pDecor->BlupiHiliMove (pos); + else + m_pDecor->CelHili (pos, 0); + } + else + m_pDecor->CelHili (pos, 0); + + return true; +} + +// Modifie le décor lorsque le bouton de la souris est relâché. + +bool +CEvent::PlayUp (Point pos) +{ + static Sounds table_sound_boing[] = { + SOUND_BOING1, + SOUND_BOING2, + SOUND_BOING3, + }; + + m_pDecor->StatisticUp (pos); + + if (m_bMouseDown) // bouton souris pressé ? + { + if (m_bHili) + m_pDecor->BlupiHiliUp (pos); + else + { + m_pDecor->BlupiGetButtons ( + pos, m_menuNb, m_menuButtons, m_menuErrors, m_menuTexts, m_menuPerso); + if (m_menuNb == 0) + m_pDecor->BlupiSound ( + -1, table_sound_boing[Random (0, countof (table_sound_boing) - 1)], + pos); + else + { + m_menuCel = m_pDecor->ConvPosToCel (pos); + m_menuPos = pos; + m_menu.Create ( + m_pPixmap, m_pSound, this, pos, m_menuNb, m_menuButtons, m_menuErrors, + m_menuTexts, m_menuPerso); + m_bMenu = true; + m_pDecor->HideTooltips (true); // plus de tooltips pour décor + } + } + } + + m_bMouseDown = false; + + return true; +} + +Language +CEvent::GetStartLanguage () +{ + if (this->m_LangStart == "en_US") + return Language::en_US; + if (this->m_LangStart == "fr") + return Language::fr; + if (this->m_LangStart == "de") + return Language::de; + if (this->m_LangStart == "it") + return Language::it; + if (this->m_LangStart == "pl") + return Language::pl; + if (this->m_LangStart == "tr") + return Language::tr; + if (this->m_LangStart == "pt") + return Language::pt; + if (this->m_LangStart == "he") + return Language::he; + return Language::en; +} + +Language +CEvent::GetLanguage () +{ + return *this->m_Lang; +} + +void +CEvent::SetLanguage (Language lang) +{ + static char env[64]; + const char * slang; + + if (lang != Language::undef) + m_Lang = m_Languages.begin () + static_cast (lang); + + switch (*m_Lang) + { + default: + case Language::undef: + case Language::en: + slang = "C"; + break; + case Language::en_US: + slang = "en_US"; + break; + case Language::fr: + slang = "fr"; + break; + case Language::de: + slang = "de"; + break; + case Language::it: + slang = "it"; + break; + case Language::pl: + slang = "pl"; + break; + case Language::tr: + slang = "tr"; + break; + case Language::pt: + slang = "pt"; + break; + case Language::he: + slang = "he"; + break; + } + + snprintf (env, sizeof (env), "LANGUAGE=%s", slang); + + { + putenv (env); +#ifndef EMSCRIPTEN + extern int _nl_msg_cat_cntr; + ++_nl_msg_cat_cntr; +#endif /* EMSCRIPTEN */ + } + + SDL_SetWindowTitle (g_window, gettext ("Planet Blupi")); + + m_pSound->CacheAll (); +} + +// Clic dans un bouton. +// Message = EV_BUTTON0..EV_BUTTON39 + +void +CEvent::ChangeButtons (Sint32 message) +{ + Buttons button; + Sint32 state, volume, max; + char * pButtonExist; + Term * pTerm; + + if (m_phase == EV_PHASE_PLAY) + { + button = m_menuButtons[message - EV_BUTTON0]; + m_pDecor->BlupiGoal (m_menuCel, button); + } + + if (m_phase == EV_PHASE_BUTTON) + { + pButtonExist = m_pDecor->GetButtonExist (); + + state = GetState (message); + if (state == 0) + state = 1; + else + state = 0; + SetState (message, state); // pressé <-> relâché + + pButtonExist[message - EV_BUTTON0] = state; + pButtonExist[BUTTON_DJEEP] = true; + pButtonExist[BUTTON_DARMOR] = true; + } + + if (m_phase == EV_PHASE_TERM) + { + pTerm = m_pDecor->GetTerminated (); + + if ( + message == EV_BUTTON1 || message == EV_BUTTON2 || message == EV_BUTTON3 || + message == EV_BUTTON8 || message == EV_BUTTON9 || + message == EV_BUTTON10 || message == EV_BUTTON11 || + message == EV_BUTTON12) + { + state = GetState (message); + if (state == 0) + state = 1; + else + state = 0; + SetState (message, state); // pressé <-> relâché + + if (message == EV_BUTTON1) + pTerm->bHachBlupi = state; + if (message == EV_BUTTON2) + pTerm->bHachPlanche = state; + if (message == EV_BUTTON3) + pTerm->bStopFire = state; + if (message == EV_BUTTON8) + pTerm->bHomeBlupi = state; + if (message == EV_BUTTON9) + pTerm->bKillRobots = state; + if (message == EV_BUTTON10) + pTerm->bHachTomate = state; + if (message == EV_BUTTON11) + pTerm->bHachMetal = state; + if (message == EV_BUTTON12) + pTerm->bHachRobot = state; + } + + if (message == EV_BUTTON4) + { + if (pTerm->nbMinBlupi > 1) + pTerm->nbMinBlupi--; + } + if (message == EV_BUTTON5) + { + if (pTerm->nbMinBlupi < 100) + pTerm->nbMinBlupi++; + } + + if (message == EV_BUTTON6) + { + if (pTerm->nbMaxBlupi > 1) + pTerm->nbMaxBlupi--; + } + if (message == EV_BUTTON7) + { + if (pTerm->nbMaxBlupi < 100) + pTerm->nbMaxBlupi++; + } + } + + if (m_phase == EV_PHASE_MUSIC) + { + m_pDecor->SetMusic (message - EV_BUTTON1); + ChangePhase (m_phase); + } + + if (m_phase == EV_PHASE_REGION) + { + m_pDecor->SetRegion (message - EV_BUTTON1); + ChangePhase (EV_PHASE_BUILD); + } + + if (m_phase == EV_PHASE_SETUP || m_phase == EV_PHASE_SETUPp) + { + if (message == EV_BUTTON1) + { + if (m_speed > 1) + m_speed = m_speed >> 1; + } + if (message == EV_BUTTON2) + { + if (m_bSpeed) + max = 8; + else + max = 2; + if (m_speed < max) + m_speed = m_speed << 1; + } + + if (message == EV_BUTTON3) + { + volume = m_pSound->GetAudioVolume (); + if (volume > 0) + m_pSound->SetAudioVolume (volume - 1); + } + if (message == EV_BUTTON4) + { + volume = m_pSound->GetAudioVolume (); + if (volume < MAXVOLUME) + m_pSound->SetAudioVolume (volume + 1); + } + + if (message == EV_BUTTON5) + { + volume = m_pSound->GetMidiVolume (); + if (volume > 0) + { + m_pSound->SetMidiVolume (volume - 1); + m_pSound->AdaptVolumeMusic (); + } + } + if (message == EV_BUTTON6) + { + volume = m_pSound->GetMidiVolume (); + if (volume < MAXVOLUME) + { + m_pSound->SetMidiVolume (volume + 1); + m_pSound->AdaptVolumeMusic (); + } + } + + if (message == EV_BUTTON7) + m_bMovie = false; + if (message == EV_BUTTON8) + m_bMovie = true; + + if (message == EV_BUTTON9) + { + if (m_scrollSpeed > 0) + m_scrollSpeed--; + } + if (message == EV_BUTTON10) + { + if (m_scrollSpeed < 3) + m_scrollSpeed++; + } + } + + if (m_phase == EV_PHASE_SETTINGS) + { + switch (message) + { + case EV_BUTTON1: + if (m_Lang != m_Languages.begin ()) + --m_Lang; + SetLanguage (); + break; + case EV_BUTTON2: + if (m_Lang != m_Languages.end () - 1) + ++m_Lang; + SetLanguage (); + break; + case EV_BUTTON3: + { + auto zoom = g_zoom; + g_zoom = g_settingsOverload & SETTING_LEGACY ? 2 : 1; + SetFullScreen (true, zoom); + break; + } + case EV_BUTTON4: + { + Sint32 w1; + SDL_GetWindowSize (g_window, &w1, nullptr); + SetFullScreen (false); + SetWindowSize (g_zoom * static_cast (w1) / LXIMAGE (), g_zoom); + break; + } + case EV_BUTTON5: + { + auto scale = g_zoom; + if (g_zoom > 1) + --g_zoom; + + if (g_bFullScreen && scale == 2) + { + SDL_Event ev; + ev.type = SDL_QUIT; + SDL_PushEvent (&ev); + g_restart = RestartMode::DESKTOP; + break; + } + + SetWindowSize (scale, g_zoom); + if (g_bFullScreen) + SetFullScreen (g_bFullScreen); + break; + } + case EV_BUTTON6: + { + auto scale = g_zoom; + if (g_zoom < 2) + ++g_zoom; + + if (g_bFullScreen && g_zoom == 2) + { + SDL_Event ev; + ev.type = SDL_QUIT; + SDL_PushEvent (&ev); + g_restart = RestartMode::LEGACY; + break; + } + + SetWindowSize (scale, g_zoom); + if (g_bFullScreen) + SetFullScreen (g_bFullScreen); + break; + } + case EV_BUTTON7: + g_restoreMidi = false; + break; + case EV_BUTTON8: + g_restoreMidi = true; + break; + case EV_BUTTON9: + g_renderQuality = false; + this->m_pPixmap->CreateMainTexture (); + break; + case EV_BUTTON10: + g_renderQuality = true; + this->m_pPixmap->CreateMainTexture (); + break; + } + } +} + +// Met un sol si nécessaire sous un objet. + +void +CEvent::BuildFloor (Point cel, Sint32 insIcon) +{ + Sint32 iFloor, channel, icon; + + if (insIcon == -1) + return; // supprime ? + + if ( + insIcon < 6 || // petite plante ? + insIcon == 117) // bateau ? + return; + + iFloor = 1; // herbe + + if ( + insIcon == 28 || // laboratoire ? + insIcon == 61 || // cabane de jardin ? + insIcon == 113 || // maison ? + insIcon == 120) // usine ? + { + iFloor = 16; // sol brun foncé + } + + if (insIcon == 122) // mine de fer ? + { + iFloor = 71; // sol avec minerai + } + + if ( + insIcon == 99 || // station de recharge ? + insIcon == 100 || // usine ennemie ? + insIcon == 102 || // usine ennemie ? + insIcon == 104 || // usine ennemie ? + (insIcon >= 106 && insIcon <= 112) || // barrière ? + insIcon == 115 || // usine ennemie ? + insIcon == 17 || // usine ennemie ? + insIcon == 12) // fusée ? + { + iFloor = 67; // sol bleu ennemi + } + + m_pDecor->GetFloor (cel, channel, icon); + if ( + (channel == CHFLOOR && icon >= 2 && icon <= 14) || // eau ou rive ? + iFloor != 1) + { + m_pDecor->PutFloor (cel, CHFLOOR, iFloor); // met un sol + m_pDecor->ArrangeFloor (cel); + } +} + +// Enlève si nécessaire un objet sur l'eau. + +void +CEvent::BuildWater (Point cel, Sint32 insIcon) +{ + Sint32 channel, icon; + + if (insIcon != 14) + return; // rien à faire si pas eau + + m_pDecor->GetObject (cel, channel, icon); + if ( + channel == CHOBJECT && icon >= 6 && // objet (pas petite plante) ? + icon != 117) // pas bateau ? + { + m_pDecor->PutObject (cel, -1, -1); // enlève l'objet + m_pDecor->ArrangeObject (cel); + } +} + +// Cette table donne les objets à construire en fonction +// du choix dans le menu. + +static Sint32 tableFloor[] = { + 1, 49, 50, 51, 0, 0, 0, 0, 0, 0, // 0 herbe + 20, 66, 79, 0, 0, 0, 0, 0, 0, 0, // 1 foncé + 33, 46, 47, 48, 71, 0, 0, 0, 0, 0, // 2 terre + 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 mer + 15, 16, 17, 18, 19, 65, 67, 0, 0, 0, // 4 dalles + 52, 80, 0, 0, 0, 0, 0, 0, 0, 0, // 5 couveuse +}; + +static Sint32 tableObject[] = { + -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 détruit + 0, 4, 1, 2, 3, 5, 0, 0, 0, 0, // 1 plantes + 6, 7, 8, 9, 10, 11, 0, 0, 0, 0, // 2 arbres + 81, 83, 94, 0, 0, 0, 0, 0, 0, 0, // 5 fleurs +}; + +static Sint32 tableHome[] = { + -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 détruit + 113, 61, 28, 120, 0, 0, 0, 0, 0, 0, // 1 maison + 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 tour de protection + 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 mine de fer + 99, 100, 102, 104, 115, 17, 12, 0, 0, 0, // 4 ennemi + 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 barrière + 26, 71, 0, 0, 0, 0, 0, 0, 0, 0, // 6 palissade + 37, 38, 39, 40, 41, 42, 43, 0, 0, 0, // 7 rochers + 36, 44, 60, 63, 80, 123, 14, 0, 0, 0, // 8 matières + 85, 125, 93, 92, 0, 0, 0, 0, 0, 0, // 9 pièges + 117, 118, 16, 0, 0, 0, 0, 0, 0, 0, // 10 véhicules +}; + +// Modifie le décor lorsque le bouton de la souris est pressé. + +bool +CEvent::BuildDown (Point pos, Uint16 mod, const SDL_Event * event, bool bMix) +{ + Point cel; + Sint32 menu, channel, icon; + + if (bMix && m_pDecor->MapMove (pos)) + return true; + + if ( + pos.x < POSDRAWX || pos.x > POSDRAWX + DIMDRAWX || pos.y < POSDRAWY || + pos.y > POSDRAWY + DIMDRAWY) + return false; + + bool isRightClick = event ? event->button.button == SDL_BUTTON_RIGHT : false; + + if (bMix) + { + m_pDecor->UndoCopy (); // copie le décor pour undo év. + } + + if (GetState (EV_DECOR1) == 1 && !isRightClick) // pose d'un sol + { + cel = m_pDecor->ConvPosToCel2 (pos); + menu = GetMenu (EV_DECOR1); + + if (!m_pDecor->GetFloor (cel, channel, icon)) + return false; + + if (bMix && tableFloor[menu * 10 + m_lastFloor[menu]] == icon) + { + m_lastFloor[menu]++; + if (tableFloor[menu * 10 + m_lastFloor[menu]] == 0) + m_lastFloor[menu] = 0; + } + + if (mod & KMOD_CTRL) // touche Ctrl enfoncée ? + { + WaitMouse (true); + m_pDecor->ArrangeFill ( + cel, CHFLOOR, tableFloor[menu * 10 + m_lastFloor[menu]], true); + WaitMouse (false); + } + else + { + icon = tableFloor[menu * 10 + m_lastFloor[menu]]; + if (menu >= 1) // met un sol ? + { + BuildWater (cel, icon); // enlève les objets + } + m_pDecor->PutFloor (cel, CHFLOOR, icon); + m_pDecor->ArrangeFloor (cel); + } + } + + if (GetState (EV_DECOR2) == 1 || isRightClick) // pose d'un objet + { + cel = m_pDecor->ConvPosToCel2 (pos); + menu = isRightClick ? 0 : GetMenu (EV_DECOR2); + + if (!m_pDecor->GetObject (cel, channel, icon)) + return false; + + if (bMix && tableObject[menu * 10 + m_lastObject[menu]] == icon) + { + m_lastObject[menu]++; + if (tableObject[menu * 10 + m_lastObject[menu]] == 0) + m_lastObject[menu] = 0; + } + + if (mod & KMOD_CTRL) // touche Ctrl enfoncée ? + { + WaitMouse (true); + m_pDecor->ArrangeFill ( + cel, CHOBJECT, tableObject[menu * 10 + m_lastObject[menu]], false); + WaitMouse (false); + } + else + { + icon = tableObject[menu * 10 + m_lastObject[menu]]; + BuildFloor (cel, icon); // met un sol si nécessaire + m_pDecor->PutObject (cel, CHOBJECT, icon); + m_pDecor->ArrangeObject (cel); + } + } + + if (GetState (EV_DECOR3) == 1 || isRightClick) // pose d'un batiment + { + cel = m_pDecor->ConvPosToCel2 (pos); + menu = isRightClick ? 0 : GetMenu (EV_DECOR3); + + if (!m_pDecor->GetObject (cel, channel, icon)) + return false; + + if (bMix && tableHome[menu * 10 + m_lastHome[menu]] == icon) + { + m_lastHome[menu]++; + if (tableHome[menu * 10 + m_lastHome[menu]] == 0) + m_lastHome[menu] = 0; + } + + if (mod & KMOD_CTRL) // touche Ctrl enfoncée ? + { + WaitMouse (true); + m_pDecor->ArrangeFill ( + cel, CHOBJECT, tableHome[menu * 10 + m_lastHome[menu]], false); + WaitMouse (false); + } + else + { + icon = tableHome[menu * 10 + m_lastHome[menu]]; + BuildFloor (cel, icon); // met un sol si nécessaire + m_pDecor->PutObject (cel, CHOBJECT, icon); + m_pDecor->ArrangeObject (cel); + } + } + + if (GetState (EV_DECOR4) == 1 || isRightClick) // pose d'un blupi + { + cel = m_pDecor->ConvPosToCel (pos); + menu = isRightClick ? 0 : GetMenu (EV_DECOR4); + + if (menu == 0) // supprime ? + m_pDecor->BlupiDelete (cel); + if (menu == 1) // ajoute blupi-fatigué ? + m_pDecor->BlupiCreate (cel, ACTION_STOP, DIRECT_S, 0, MAXENERGY / 4); + if (menu == 2) // ajoute blupi-énergique ? + m_pDecor->BlupiCreate (cel, ACTION_STOP, DIRECT_S, 0, MAXENERGY); + if (menu == 3) // ajoute assistant ? + m_pDecor->BlupiCreate (cel, ACTION_STOP, DIRECT_S, 8, MAXENERGY); + if (menu == 4) // ajoute araignée ? + m_pDecor->BlupiCreate (cel, ACTION_STOP, DIRECT_S, 1, MAXENERGY); + if (menu == 5) // ajoute virus ? + m_pDecor->BlupiCreate (cel, ACTION_STOP, DIRECT_S, 2, MAXENERGY); + if (menu == 6) // ajoute tracks ? + m_pDecor->BlupiCreate (cel, ACTION_STOP, DIRECT_S, 3, MAXENERGY); + if (menu == 7) // ajoute bombe ? + m_pDecor->BlupiCreate (cel, ACTION_STOP, DIRECT_S, 5, MAXENERGY); + if (menu == 8) // ajoute électro ? + m_pDecor->BlupiCreate (cel, ACTION_STOP, DIRECT_S, 7, MAXENERGY); + if (menu == 9) // ajoute robot ? + m_pDecor->BlupiCreate (cel, ACTION_STOP, DIRECT_S, 4, MAXENERGY); + } + + if (GetState (EV_DECOR5) == 1 || isRightClick) // pose d'une cata + { + cel = m_pDecor->ConvPosToCel2 (pos); + menu = isRightClick ? 0 : GetMenu (EV_DECOR5); + + if (menu == 0) // supprime ? + m_pDecor->SetFire (cel, false); + + if (menu == 1 && (g_restoreBugs || m_pDecor->CanBurn (cel))) // ajoute ? + m_pDecor->SetFire (cel, true); + } + + m_pDecor->ArrangeBlupi (); // supprime les blupi bloqués + + return true; +} + +// Modifie le décor lorsque la souris est déplacée. + +bool +CEvent::BuildMove (Point pos, Uint16 mod, const SDL_Event & event) +{ + if (event.motion.state & SDL_BUTTON (SDL_BUTTON_LEFT)) // bouton souris pressé + BuildDown (pos, mod, nullptr, false); + + if (GetState (EV_DECOR4) == 1) // pose d'un blupi + m_pDecor->CelHili (pos, 1); + else + m_pDecor->CelHili (pos, 2); + + return true; +} + +// Démarre un film non interractif. + +bool +CEvent::StartMovie (const std::string & pFilename) +{ + if (!m_pMovie->GetEnable ()) + return false; + if (!m_bMovie) + return false; + + std::string absolute; + if (!FileExists (pFilename, absolute)) + return false; + + HideMouse (true); + m_pSound->StopMusic (); + + if (!m_pMovie->Play (pFilename)) + return false; + + m_bRunMovie = true; + return true; +} + +// Stoppe un film non interractif. + +void +CEvent::StopMovie () +{ + m_pMovie->Stop (); + ChangePhase (m_phase); + m_bRunMovie = false; +} + +// Indique s'il y a un film en cours. + +bool +CEvent::IsMovie () +{ + return m_bRunMovie; +} + +// Lit une partie (user000.blp). + +void +CEvent::Read (Sint32 message) +{ + Sint32 world, time, total; + + m_pDecor->Read (message - EV_READ0, true, world, time, total); + m_pDecor->SetTime (time); + m_pDecor->SetTotalTime (total); + + if (world >= 200) + { + m_private = world - 200; + m_bSchool = false; + m_bPrivate = true; + } + else if (world >= 100) + { + m_mission = world - 100; + m_bSchool = false; + m_bPrivate = false; + } + else + { + m_exercice = world; + m_bSchool = true; + m_bPrivate = false; + } +} + +// Ecrit une partie (user000.blp). + +void +CEvent::Write (Sint32 message) +{ + Sint32 time, total; + + time = m_pDecor->GetTime (); + total = m_pDecor->GetTotalTime (); + + m_pDecor->Write (message - EV_WRITE0, true, GetPhysicalWorld (), time, total); +} + +// Initialise le libellé d'une mission privée. + +void +CEvent::PrivateLibelle () +{ + Sint32 i, nb, h1, h2; + Term term; + char string[100]; + char buffer[100]; + const char * text = nullptr; + + snprintf (m_libelle, sizeof (m_libelle), "%s", gettext ("1|Goal :")); + + memcpy (&term, m_pDecor->GetTerminated (), sizeof (Term)); + nb = 0; + for (i = 0; i < 2; i++) // 2 objectifs au maximum ! + { + text = nullptr; + + if (term.bKillRobots) + { + term.bKillRobots = false; + text = gettext ("1|Kill all\n1|enemies !"); + } + else if (term.bHachBlupi) + { + term.bHachBlupi = false; + text = gettext ("1|Go on striped\n1|paving stones."); + } + else if (term.bHachPlanche) + { + term.bHachPlanche = false; + text = gettext ("1|Drop planks on striped \n1|paving stones."); + } + else if (term.bHachTomate) + { + term.bHachTomate = false; + text = gettext ("1|Drop tomatoes on striped \n1|paving stones."); + } + else if (term.bHachMetal) + { + term.bHachMetal = false; + text = gettext ("1|Drop platinium on striped \n1|paving stones."); + } + else if (term.bHachRobot) + { + term.bHachRobot = false; + text = gettext ("1|The robot must reach\n1|the striped paving stones."); + } + else if (term.bHomeBlupi) + { + term.bHomeBlupi = false; + text = gettext ("1|Each Blupi in\n1|his house."); + } + else if (term.bStopFire) + { + term.bStopFire = false; + text = gettext ("1|Resist until\n1|fire extinction ..."); + } + + if (!text) + break; + + strcat (m_libelle, "\n1|\n"); + strcat (m_libelle, text); + nb++; + } + + if (nb == 0 || term.nbMaxBlupi > 1) + { + snprintf ( + buffer, sizeof (buffer), "%s", + gettext ("1|The Blupi population must\n1|be of at least %d Blupi.")); + snprintf (string, sizeof (string), buffer, term.nbMaxBlupi); + strcat (m_libelle, "\n1|\n"); + strcat (m_libelle, string); + } + + h1 = GetTextHeight (m_libelle, FONTLITTLE, 1); + h2 = GetTextHeight (m_libelle, FONTLITTLE, 2); + if (h2 > h1) + h1 = h2; + m_pDecor->SetInfoHeight (POSDRAWY + h1 + 10); +} + +// Lit le libellé d'un monde. + +bool +CEvent::ReadLibelle (Sint32 world, bool bSchool, bool bHelp) +{ + FILE * file = nullptr; + char * pBuffer = nullptr; + char * pText; + char * pDest; + char indic; + Sint32 h1, h2; + size_t nb; + + if (bSchool) + indic = '$'; + else + indic = '#'; + if (bHelp) + indic = '@'; + + auto stories = GetBaseDir () + "data/" + GetLocale () + "/stories.blp"; + + pBuffer = (char *) malloc (sizeof (char) * 50000); + if (pBuffer == nullptr) + goto error; + + memset (pBuffer, 0, sizeof (char) * 50000); + + file = fopen (stories.c_str (), "rb"); + if (file == nullptr) + { + /* Try with the fallback locale */ + stories = GetBaseDir () + "data/en/stories.blp"; + file = fopen (stories.c_str (), "rb"); + if (!file) + goto error; + } + + nb = fread (pBuffer, sizeof (char), 50000 - 1, file); + pBuffer[nb] = 0; + + pText = pBuffer; + while (world >= 0) + { + while (*pText != 0 && *pText != indic) + pText++; + if (*pText == indic) + pText++; + world--; + } + while (*pText != 0 && *pText != '\n') + pText++; + if (*pText == '\n') + pText++; + pDest = m_libelle; + while (*pText != 0 && *pText != indic && *pText != '$' && *pText != '#' && + *pText != '@') + *pDest++ = *pText++; + *pDest = 0; + + h1 = GetTextHeight (m_libelle, FONTLITTLE, 1); + h2 = GetTextHeight (m_libelle, FONTLITTLE, 2); + if (h2 > h1) + h1 = h2; + m_pDecor->SetInfoHeight (POSDRAWY + h1 + 10); + + free (pBuffer); + fclose (file); + return true; + +error: + if (pBuffer != nullptr) + free (pBuffer); + if (file != nullptr) + fclose (file); + return false; +} + +// Sauve les informations sur disque. + +bool +CEvent::WriteInfo () +{ + std::string filename; + FILE * file = nullptr; + DescInfo info = {0}; + size_t nb; + + filename = "data/info.blp"; + AddUserPath (filename); + + file = fopen (filename.c_str (), "wb"); + if (file == nullptr) + goto error; + + info.majRev = 1; + info.minRev = 3; + info.prive = m_private; + info.exercice = m_exercice; + info.mission = m_mission; + info.maxMission = m_maxMission; + info.speed = m_speed; + info.bMovie = m_bMovie; + info.scrollSpeed = m_scrollSpeed; + info.bAccessBuild = m_bAccessBuild; + + info.skill = m_pDecor->GetSkill (); + + info.audioVolume = m_pSound->GetAudioVolume (); + info.midiVolume = m_pSound->GetMidiVolume (); + + /* Global settings */ + info.language = static_cast ( + this->GetLanguage () != this->GetStartLanguage () ? this->GetLanguage () + : Language::undef); + info.musicMidi = g_restoreMidi; + info.fullScreen = g_bFullScreen; + info.zoom = g_zoom; + info.renderQuality = g_renderQuality; + + nb = fwrite (&info, sizeof (info), 1, file); + if (nb < 1) + goto error; + + fclose (file); + return true; + +error: + if (file != nullptr) + fclose (file); + return false; +} + +// Lit les informations sur disque. + +bool +CEvent::ReadInfo () +{ + std::string filename; + FILE * file = nullptr; + DescInfo info; + size_t nb; + + filename = "data/info.blp"; + AddUserPath (filename); + + file = fopen (filename.c_str (), "rb"); + if (file == nullptr) + goto error; + + SDL_memset (&info, 0, sizeof (info)); + + nb = fread (&info, sizeof (DescInfo), 1, file); + if (nb < 1) + goto error; + + m_private = info.prive; + m_exercice = info.exercice; + m_mission = info.mission; + m_maxMission = info.maxMission; + m_speed = info.speed; + m_bMovie = !!info.bMovie; + m_scrollSpeed = info.scrollSpeed; + m_bAccessBuild = !!info.bAccessBuild; + + m_pDecor->SetSkill (info.skill); + + m_pSound->SetAudioVolume (info.audioVolume); + m_pSound->SetMidiVolume (info.midiVolume); + + if ((info.majRev == 1 && info.minRev >= 1) || info.majRev >= 2) + { + if (info.language >= static_cast (Language::end)) + info.language = 0; + this->SetLanguage (static_cast (info.language)); + } + + if (((info.majRev == 1 && info.minRev >= 2) || info.majRev >= 2)) + { + if (!(g_settingsOverload & SETTING_MIDI)) + g_restoreMidi = !!info.musicMidi; + if (!(g_settingsOverload & SETTING_FULLSCREEN)) + g_bFullScreen = !!info.fullScreen; + if (!(g_settingsOverload & SETTING_ZOOM)) + g_zoom = info.zoom; + + /* Prefer the desktop fullscreen mode by default. */ + if (!(g_settingsOverload & SETTING_LEGACY) && g_bFullScreen && g_zoom == 2) + g_zoom = 1; + } + + if (((info.majRev == 1 && info.minRev >= 3) || info.majRev >= 2)) + { + if (!(g_settingsOverload & SETTING_RENDERQUALITY)) + g_renderQuality = !!info.renderQuality; + } + + fclose (file); + return true; + +error: + if (file != nullptr) + fclose (file); + return false; +} + +// Modifie la vitesse du jeu. + +void +CEvent::SetSpeed (Sint32 speed) +{ + Sint32 max; + + if (m_bSpeed) + max = 8; + else + max = 2; + + if (speed > max) + speed = max; + + m_speed = speed; +} + +Sint32 +CEvent::GetSpeed () +{ + return m_speed; +} + +bool +CEvent::GetPause () +{ + return m_bPause; +} + +// Début de l'enregistrement d'une démo. + +void +CEvent::DemoRecStart () +{ + m_pDemoSDLBuffer.clear (); + m_demoTime = 0; + m_demoIndex = 0; + m_bDemoRec = true; + m_bDemoPlay = false; + + InitRandom (); + m_pDecor->SetTime (0); + m_speed = 1; + + if (this->m_scrollSpeedPrev == -1) + this->m_scrollSpeedPrev = this->m_scrollSpeed; + this->m_scrollSpeed = 3; + + m_bStartRecording = true; +} + +// Fin de l'enregistrement d'une démo. +// Sauve le fichier sur disque. + +void +CEvent::DemoRecStop () +{ + FILE * file = nullptr; + DemoHeader header; + + if (m_bDemoPlay || !m_bDemoRec) + return; + + std::time_t t = std::time (nullptr); + std::localtime (&t); + std::string demoPath = "demo/demo." + std::to_string (t) + ".blp"; + AddUserPath (demoPath); + + unlink (demoPath.c_str ()); + file = fopen (demoPath.c_str (), "wb"); + if (file) + { + memset (&header, 0, sizeof (DemoHeader)); + header.majRev = 2; + header.minRev = 0; + header.bSchool = m_bSchool; + header.bPrivate = m_bPrivate; + header.world = GetPhysicalWorld (); + header.skill = m_pDecor->GetSkill (); + + fwrite (&header, sizeof (DemoHeader), 1, file); + for (const auto buffer : m_pDemoSDLBuffer) + fwrite (&buffer, sizeof (DemoSDLEvent), 1, file); + fclose (file); + } + + m_pDemoSDLBuffer.clear (); + m_bDemoRec = false; + m_demoTime = 0; + m_bStartRecording = false; + + if (this->m_scrollSpeedPrev >= 0) + { + this->m_scrollSpeed = this->m_scrollSpeedPrev; + this->m_scrollSpeedPrev = -1; + } +} + +// Début de la reproduction d'une démo. +// Lit le fichier sur disque. + +bool +CEvent::DemoPlayStart (const std::string * demoFile) +{ + std::string filename; + FILE * file = nullptr; + DemoHeader header; + Sint32 world, time, total; + size_t nb; + + filename = + demoFile + ? *demoFile + : string_format (GetBaseDir () + "data/demo%.3d.blp", m_demoNumber); + file = fopen (filename.c_str (), "rb"); + if (file == nullptr) + { + DemoPlayStop (); + return false; + } + + nb = fread (&header, sizeof (DemoHeader), 1, file); + if (nb < 1) + { + fclose (file); + DemoPlayStop (); + return false; + } + + if (header.majRev == 1) + { + m_pDemoBuffer = (DemoEvent *) malloc (MAXDEMO * sizeof (DemoEvent)); + if (m_pDemoBuffer == nullptr) + { + fclose (file); + DemoPlayStop (); + return false; + } + memset (m_pDemoBuffer, 0, MAXDEMO * sizeof (DemoEvent)); + } + + m_bSchool = !!header.bSchool; + m_bPrivate = !!header.bPrivate; + m_pDecor->SetSkill (header.skill); + + if (header.majRev == 1) + m_demoEnd = fread (m_pDemoBuffer, sizeof (DemoEvent), MAXDEMO, file); + else if (header.majRev == 2) + { + DemoSDLEvent demoEvent; + + for (;;) + { + auto res = fread (&demoEvent, sizeof (DemoSDLEvent), 1, file); + if (res != 1) + break; + + m_pDemoSDLBuffer.push_back (demoEvent); + } + + m_demoEnd = m_pDemoSDLBuffer.size (); + } + fclose (file); + + m_demoTime = 0; + m_demoIndex = 0; + m_bDemoPlay = true; + m_bDemoRec = false; + + if (!m_pDecor->Read (header.world, false, world, time, total)) + { + DemoPlayStop (); + return false; + } + + if (this->m_scrollSpeedPrev == -1) + this->m_scrollSpeedPrev = this->m_scrollSpeed; + this->m_scrollSpeed = 3; + + ChangePhase (EV_PHASE_PLAY); + InitRandom (); + m_pDecor->SetTime (0); + m_speed = 1; + + return true; +} + +// Fin de la reproduction d'une démo. + +void +CEvent::DemoPlayStop () +{ + if (m_pDemoBuffer != nullptr) + { + free (m_pDemoBuffer); + m_pDemoBuffer = nullptr; + } + + m_pDemoSDLBuffer.clear (); + + m_bDemoPlay = false; + m_bDemoRec = false; + m_demoTime = 0; + + if (this->m_scrollSpeedPrev >= 0) + { + this->m_scrollSpeed = this->m_scrollSpeedPrev; + this->m_scrollSpeedPrev = -1; + } + + ChangePhase (EV_PHASE_INIT); +} + +void +CEvent::WinToSDLEvent ( + Uint32 msg, WParam wParam, LParam lParam, SDL_Event & event) +{ +#define GET_X_LParam(lp) ((Sint32) (Sint16) LOWORD (lp)) +#define GET_Y_LParam(lp) ((Sint32) (Sint16) HIWORD (lp)) + + // clang-format off + static const std::unordered_map keycodes = { + { '0', { SDL_SCANCODE_0, SDLK_0, 0, 0 } }, + { '1', { SDL_SCANCODE_1, SDLK_1, 0, 0 } }, + { '2', { SDL_SCANCODE_2, SDLK_2, 0, 0 } }, + { '3', { SDL_SCANCODE_3, SDLK_3, 0, 0 } }, + { '4', { SDL_SCANCODE_4, SDLK_4, 0, 0 } }, + { '5', { SDL_SCANCODE_5, SDLK_5, 0, 0 } }, + { '6', { SDL_SCANCODE_6, SDLK_6, 0, 0 } }, + { '7', { SDL_SCANCODE_7, SDLK_7, 0, 0 } }, + { '8', { SDL_SCANCODE_8, SDLK_8, 0, 0 } }, + { '9', { SDL_SCANCODE_9, SDLK_9, 0, 0 } }, + { 'A', { SDL_SCANCODE_A, SDLK_a, 0, 0 } }, + { 'B', { SDL_SCANCODE_B, SDLK_b, 0, 0 } }, + { 'C', { SDL_SCANCODE_C, SDLK_c, 0, 0 } }, + { 'D', { SDL_SCANCODE_D, SDLK_d, 0, 0 } }, + { 'E', { SDL_SCANCODE_E, SDLK_e, 0, 0 } }, + { 'F', { SDL_SCANCODE_F, SDLK_f, 0, 0 } }, + { 'G', { SDL_SCANCODE_G, SDLK_g, 0, 0 } }, + { 'H', { SDL_SCANCODE_H, SDLK_h, 0, 0 } }, + { 'I', { SDL_SCANCODE_I, SDLK_i, 0, 0 } }, + { 'J', { SDL_SCANCODE_J, SDLK_j, 0, 0 } }, + { 'K', { SDL_SCANCODE_K, SDLK_k, 0, 0 } }, + { 'L', { SDL_SCANCODE_L, SDLK_l, 0, 0 } }, + { 'M', { SDL_SCANCODE_M, SDLK_m, 0, 0 } }, + { 'N', { SDL_SCANCODE_N, SDLK_n, 0, 0 } }, + { 'O', { SDL_SCANCODE_O, SDLK_o, 0, 0 } }, + { 'P', { SDL_SCANCODE_P, SDLK_p, 0, 0 } }, + { 'Q', { SDL_SCANCODE_Q, SDLK_q, 0, 0 } }, + { 'R', { SDL_SCANCODE_R, SDLK_r, 0, 0 } }, + { 'S', { SDL_SCANCODE_S, SDLK_0, 0, 0 } }, + { 'T', { SDL_SCANCODE_T, SDLK_t, 0, 0 } }, + { 'U', { SDL_SCANCODE_U, SDLK_u, 0, 0 } }, + { 'V', { SDL_SCANCODE_V, SDLK_v, 0, 0 } }, + { 'W', { SDL_SCANCODE_W, SDLK_w, 0, 0 } }, + { 'X', { SDL_SCANCODE_X, SDLK_x, 0, 0 } }, + { 'Y', { SDL_SCANCODE_Y, SDLK_y, 0, 0 } }, + { 'Z', { SDL_SCANCODE_Z, SDLK_z, 0, 0 } }, + { VK_LEFT, { SDL_SCANCODE_LEFT, SDLK_LEFT, 0, 0 } }, + { VK_UP, { SDL_SCANCODE_UP, SDLK_UP, 0, 0 } }, + { VK_RIGHT, { SDL_SCANCODE_RIGHT, SDLK_RIGHT, 0, 0 } }, + { VK_DOWN, { SDL_SCANCODE_DOWN, SDLK_DOWN, 0, 0 } }, + { VK_END, { SDL_SCANCODE_END, SDLK_END, 0, 0 } }, + }; + // clang-format on + + try + { + switch (msg) + { + case EV_KEYUP: + case EV_KEYDOWN: + event.type = msg == EV_KEYDOWN ? SDL_KEYDOWN : SDL_KEYUP; + event.key.keysym = keycodes.at (wParam); + // TODO: lParam + break; + + case EV_LBUTTONUP: + case EV_LBUTTONDOWN: + event.type = + msg == EV_LBUTTONDOWN ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP; + event.button.button = SDL_BUTTON_LEFT; + // TODO: wParam CTRL or SHIFT + event.button.x = GET_X_LParam (lParam); + event.button.y = GET_Y_LParam (lParam); + break; + + case EV_RBUTTONUP: + case EV_RBUTTONDOWN: + event.type = + msg == EV_RBUTTONDOWN ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP; + event.button.button = SDL_BUTTON_RIGHT; + // TODO: wParam CTRL or SHIFT + event.button.x = GET_X_LParam (lParam); + event.button.y = GET_Y_LParam (lParam); + break; + + case EV_MOUSEMOVE: + event.type = SDL_MOUSEMOTION; + // TODO: wParam CTRL or SHIFT + event.motion.x = GET_X_LParam (lParam); + event.motion.y = GET_Y_LParam (lParam); + break; + } + } + catch (...) + { + SDL_LogError (SDL_LOG_CATEGORY_APPLICATION, "unsupported keycode"); + } +} + +// Avance l'index d'enregistrement ou de reproduction. + +void +CEvent::DemoStep () +{ + Uint32 time = 0; + Uint32 message = 0; + WParam wParam = 0; + LParam lParam = 0; + + if (m_phase == EV_PHASE_INIT) + { + if (!g_playRecord.empty ()) + { + m_demoNumber = -1; + DemoPlayStart (&g_playRecord); + g_playRecord = ""; + } + else if (m_demoTime > DEF_TIME_DEMO) // ~30 secondes écoulées ? + { + m_demoNumber = 0; + DemoPlayStart (); // démarre une démo automatique + } + } + + if (m_bDemoPlay) + { + while (true) + { + SDL_Event event = {0}; + + if (m_pDemoBuffer) // Old Win32 events format + { + time = m_pDemoBuffer[m_demoIndex].time; + message = m_pDemoBuffer[m_demoIndex].message; + wParam = m_pDemoBuffer[m_demoIndex].wParam; + lParam = m_pDemoBuffer[m_demoIndex].lParam; + + if (IsRightReading ()) + lParam = + (lParam & 0xFFFF0000) | ((lParam & 0xFFFF) - POSDRAWX_ + POSDRAWX); + } + else // New SDL events format + { + time = m_pDemoSDLBuffer[m_demoIndex].time; + event.type = m_pDemoSDLBuffer[m_demoIndex].type; + event.key.keysym.scancode = + static_cast (m_pDemoSDLBuffer[m_demoIndex].scancode); + event.key.keysym.sym = m_pDemoSDLBuffer[m_demoIndex].sym; + if (event.type == SDL_MOUSEMOTION) + { + event.motion.x = m_pDemoSDLBuffer[m_demoIndex].x; + event.motion.y = m_pDemoSDLBuffer[m_demoIndex].y; + + if (IsRightReading ()) + event.motion.x -= POSDRAWX_ + POSDRAWX; + } + else if (event.type != SDL_KEYUP && event.type != SDL_KEYDOWN) + { + event.button.button = m_pDemoSDLBuffer[m_demoIndex].button; + event.button.x = m_pDemoSDLBuffer[m_demoIndex].x; + event.button.y = m_pDemoSDLBuffer[m_demoIndex].y; + + if (IsRightReading ()) + event.button.x -= POSDRAWX_ + POSDRAWX; + } + } + + if (time > m_demoTime) + break; + + m_demoIndex++; + + if (message == EV_MOUSEMOVE || event.type == SDL_MOUSEMOTION) + { + Point pos; + + if (m_pDemoBuffer) + pos = ConvLongToPos (lParam); + else + { + pos.x = event.motion.x; + pos.y = event.motion.y; + } + + this->m_pPixmap->FromGameToDisplay (pos.x, pos.y); + SDL_WarpMouseInWindow (g_window, pos.x, pos.y); + } + + if (m_pDemoBuffer) + CEvent::WinToSDLEvent (message, wParam, lParam, event); + + TreatEventBase (event); + + if (m_demoIndex >= m_demoEnd && m_demoNumber >= 0) + { + m_demoNumber++; // démo suivante + if (!DemoPlayStart ()) // démarre la démo suivante + { + m_demoNumber = 0; // première démo + DemoPlayStart (); // démarre la démo + } + return; + } + } + } + + m_demoTime++; +} + +/** + * \brief Store an event for the demos + */ +void +CEvent::DemoRecEvent (const SDL_Event & event) +{ + if (!m_bDemoRec) + return; + + DemoSDLEvent demoEvent = {0}; + + switch (event.type) + { + case SDL_KEYUP: + case SDL_KEYDOWN: + demoEvent.type = event.type; + demoEvent.time = m_demoTime; + demoEvent.scancode = event.key.keysym.scancode; + demoEvent.sym = event.key.keysym.sym; + break; + + case SDL_MOUSEBUTTONUP: + case SDL_MOUSEBUTTONDOWN: + demoEvent.type = event.type; + demoEvent.time = m_demoTime; + demoEvent.button = event.button.button; + demoEvent.x = event.button.x; + demoEvent.y = event.button.y; + this->m_pPixmap->FromDisplayToGame (demoEvent.x, demoEvent.y); + break; + + case SDL_MOUSEMOTION: + demoEvent.type = event.type; + demoEvent.time = m_demoTime; + demoEvent.x = event.motion.x; + demoEvent.y = event.motion.y; + this->m_pPixmap->FromDisplayToGame (demoEvent.x, demoEvent.y); + break; + + default: + return; + } + + m_pDemoSDLBuffer.push_back (demoEvent); + + m_demoIndex = m_pDemoSDLBuffer.size (); +} + +// Retourne la dernière position de la souris. + +Point +CEvent::GetLastMousePos () +{ + return m_oldMousePos; +} + +// Traitement d'un événement. + +bool +CEvent::TreatEvent (const SDL_Event & event) +{ + if (m_bDemoPlay) + { + if ( + event.type == SDL_KEYDOWN || event.type == SDL_KEYUP || + event.type == SDL_MOUSEBUTTONUP) // is the user clicking? + { + DemoPlayStop (); + return true; + } + + if (event.type == SDL_MOUSEMOTION) // is the user moving? + return true; + } + + return TreatEventBase (event); +} + +// Traitement d'un événement. + +bool +CEvent::TreatEventBase (const SDL_Event & event) +{ + Point pos; + Sint32 i; + Sounds sound; + char c; + bool bEnable; + + DemoRecEvent (event); + + switch (event.type) + { + case SDL_KEYDOWN: + if (event.key.keysym.sym >= SDLK_a && event.key.keysym.sym <= SDLK_z) + { + if (m_posCheat == 0) // première lettre ? + { + m_rankCheat = -1; + for (i = 0; i < 9; i++) + { + if ((char) event.key.keysym.sym == cheat_code[i][0]) + { + m_rankCheat = i; + break; + } + } + } + if (m_rankCheat != -1) + { + c = cheat_code[m_rankCheat][m_posCheat]; + if (m_posCheat != 0 && m_rankCheat == 8) + c++; // CONSTRUIRE ? + if ((char) event.key.keysym.sym == c) + { + m_posCheat++; + if (cheat_code[m_rankCheat][m_posCheat] == 0) + { + bEnable = true; + if (m_phase == EV_PHASE_PLAY) + { + if (m_rankCheat == 0) // vision ? + m_pDecor->EnableFog (false); + else if ( + m_rankCheat == 1 || // power ? + m_rankCheat == 2) // lonesome ? + m_pDecor->BlupiCheat (m_rankCheat); + } + + switch (m_rankCheat) + { + case 3: // allmissions ? + { + m_bAllMissions = !m_bAllMissions; + bEnable = m_bAllMissions; + break; + } + case 4: // quick ? + { + m_bSpeed = !m_bSpeed; + bEnable = m_bSpeed; + break; + } + case 5: // helpme ? + { + m_bHelp = !m_bHelp; + bEnable = m_bHelp; + break; + } + case 6: // invincible ? + { + m_pDecor->SetInvincible (!m_pDecor->GetInvincible ()); + bEnable = m_pDecor->GetInvincible (); + break; + } + case 7: // superblupi ? + { + m_pDecor->SetSuper (!m_pDecor->GetSuper ()); + bEnable = m_pDecor->GetSuper (); + break; + } + case 8: // construire ? + { + m_bAccessBuild = !m_bAccessBuild; + bEnable = m_bAccessBuild; + break; + } + } + + if (m_phase != EV_PHASE_PLAY) + ChangePhase (m_phase); + + pos.x = LXIMAGE () / 2; + pos.y = LYIMAGE () / 2; + if (bEnable) + m_pSound->PlayImage (SOUND_GOAL, pos); + else + m_pSound->PlayImage (SOUND_BOING, pos); + + m_rankCheat = -1; + m_posCheat = 0; + } + return true; + } + } + } + m_rankCheat = -1; + m_posCheat = 0; + + if (m_phase == EV_PHASE_INTRO1) + { + ChangePhase (EV_PHASE_INIT); + return true; + } + + if (m_phase == EV_PHASE_BYE) + { + SDL_Event ev; + ev.type = SDL_QUIT; + SDL_PushEvent (&ev); + } + + switch (event.key.keysym.sym) + { + case SDLK_END: + DemoRecStop (); + return true; + case SDLK_ESCAPE: + if (m_bRunMovie) + { + StopMovie (); + return true; + } + + switch (m_phase) + { + case EV_PHASE_PLAY: + case EV_PHASE_SETUPp: + case EV_PHASE_WRITE: + case EV_PHASE_WRITEp: + case EV_PHASE_HELP: + ChangePhase (EV_PHASE_STOP); + return true; + + case EV_PHASE_SETUP: + case EV_PHASE_READ: + ChangePhase ( + this->m_pDecor->GetTime () ? EV_PHASE_STOP : EV_PHASE_INFO); + return true; + + case EV_PHASE_STOP: + ChangePhase (EV_PHASE_PLAY); + return true; + + case EV_PHASE_LOST: + case EV_PHASE_BUILD: + ChangePhase (EV_PHASE_INFO); + return true; + + case EV_PHASE_INFO: + case EV_PHASE_SETTINGS: + ChangePhase (EV_PHASE_INIT); + return true; + + case EV_PHASE_BUTTON: + case EV_PHASE_TERM: + case EV_PHASE_MUSIC: + case EV_PHASE_REGION: + ChangePhase (EV_PHASE_BUILD); + return true; + + case EV_PHASE_INIT: + ChangePhase (EV_PHASE_BYE); + return true; + + case EV_PHASE_BYE: + { + SDL_Event ev; + ev.type = SDL_QUIT; + SDL_PushEvent (&ev); + break; + } + } + return true; + case SDLK_RETURN: + switch (m_phase) + { + case EV_PHASE_SETTINGS: + ChangePhase (EV_PHASE_INIT); + return true; + + case EV_PHASE_PLAY: + case EV_PHASE_WRITE: + ChangePhase (EV_PHASE_STOP); + return true; + + case EV_PHASE_SETUP: + case EV_PHASE_READ: + ChangePhase ( + this->m_pDecor->GetTime () ? EV_PHASE_STOP : EV_PHASE_INFO); + return true; + + case EV_PHASE_INIT: + case EV_PHASE_LOST: + case EV_PHASE_BUILD: + ChangePhase (EV_PHASE_INFO); + return true; + + case EV_PHASE_INFO: + case EV_PHASE_STOP: + case EV_PHASE_HELP: + case EV_PHASE_SETUPp: + case EV_PHASE_WRITEp: + ChangePhase (EV_PHASE_PLAY); + return true; + + case EV_PHASE_BUTTON: + case EV_PHASE_TERM: + case EV_PHASE_MUSIC: + case EV_PHASE_REGION: + ChangePhase (EV_PHASE_BUILD); + return true; + } + + return true; + case SDLK_LEFT: + case SDLK_RIGHT: + case SDLK_UP: + case SDLK_DOWN: + { + if (m_phase != EV_PHASE_PLAY && m_phase != EV_PHASE_BUILD) + return true; + + bool left, right, up, down; + const Uint8 * state = SDL_GetKeyboardState (nullptr); + + this->shiftDirection = 0; + + left = event.key.keysym.sym == SDLK_LEFT || + (!m_bDemoRec && state[SDL_SCANCODE_LEFT]); + right = event.key.keysym.sym == SDLK_RIGHT || + (!m_bDemoRec && state[SDL_SCANCODE_RIGHT]); + up = event.key.keysym.sym == SDLK_UP || + (!m_bDemoRec && state[SDL_SCANCODE_UP]); + down = event.key.keysym.sym == SDLK_DOWN || + (!m_bDemoRec && state[SDL_SCANCODE_DOWN]); + + if (left) + this->shiftDirection |= DIRECTION_LEFT; + if (right) + this->shiftDirection |= DIRECTION_RIGHT; + if (up) + this->shiftDirection |= DIRECTION_UP; + if (down) + this->shiftDirection |= DIRECTION_DOWN; + return true; + } + case SDLK_HOME: + pos = m_pDecor->GetHome (); + m_pDecor->SetCorner (pos); + return true; + case SDLK_SPACE: + if (m_bRunMovie) + { + StopMovie (); + return true; + } + m_pDecor->FlipOutline (); + return true; + case SDLK_PAUSE: + if (this->m_pDecor->GetSkill () >= 1) + return true; + + m_bPause = !m_bPause; + if (m_phase == EV_PHASE_PLAY) + { + if (m_bPause) + m_pSound->SuspendMusic (); + else + m_pSound->RestartMusic (); + } + return true; + + case SDLK_LSHIFT: + case SDLK_RSHIFT: + m_keymod |= KMOD_SHIFT; + break; + + case SDLK_LCTRL: + case SDLK_RCTRL: + m_keymod |= KMOD_CTRL; + if (m_phase == EV_PHASE_BUILD) + m_bFillMouse = true; + else + m_bFillMouse = false; + return true; + case SDLK_F1: + if (m_phase == EV_PHASE_PLAY) + { + // Montre ou cache les infos tout en haut. + if (m_pDecor->GetInfoMode ()) + sound = SOUND_CLOSE; + else + sound = SOUND_OPEN; + pos.x = LXIMAGE () / 2; + pos.y = LYIMAGE () / 2; + m_pSound->PlayImage (sound, pos); + m_pDecor->SetInfoMode (!m_pDecor->GetInfoMode ()); + } + return true; + case SDLK_F3: + if ( + g_enableRecorder && m_phase == EV_PHASE_PLAY && !m_bDemoPlay && + !m_bStartRecording) + DemoRecStart (); // start recording + break; + case SDLK_F4: + if ( + g_enableRecorder && m_phase == EV_PHASE_PLAY && !m_bDemoPlay && + m_bStartRecording) + DemoRecStop (); // stop recording + else if (m_phase == EV_PHASE_PLAY && m_bDemoPlay) + { + DemoPlayStop (); + return true; + } + break; + case SDLK_F9: + if (m_phase == EV_PHASE_PLAY) + m_pDecor->MemoPos (0, !!(m_keymod & KMOD_CTRL)); + return true; + case SDLK_F10: + if (m_phase == EV_PHASE_PLAY) + m_pDecor->MemoPos (1, !!(m_keymod & KMOD_CTRL)); + return true; + case SDLK_F11: + if (m_phase == EV_PHASE_PLAY) + m_pDecor->MemoPos (2, !!(m_keymod & KMOD_CTRL)); + return true; + case SDLK_F12: + if (m_phase == EV_PHASE_PLAY) + m_pDecor->MemoPos (3, !!(m_keymod & KMOD_CTRL)); + return true; + } + break; + + case SDL_KEYUP: + switch (event.key.keysym.sym) + { + case SDLK_LSHIFT: + case SDLK_RSHIFT: + m_keymod &= ~KMOD_SHIFT; + break; + + case SDLK_LCTRL: + case SDLK_RCTRL: + m_keymod &= ~KMOD_CTRL; + m_bFillMouse = false; + return true; + } + break; + + case SDL_MOUSEBUTTONDOWN: + if ( + event.button.button != SDL_BUTTON_LEFT && + event.button.button != SDL_BUTTON_RIGHT) + break; + + pos.x = event.button.x; + pos.y = event.button.y; + + if (EventButtons (event, pos)) + return true; + if (m_phase == EV_PHASE_BUILD) + { + if (BuildDown (pos, m_keymod, &event)) + return true; + } + if (m_phase == EV_PHASE_PLAY) + { + if (PlayDown (pos, event)) + return true; + } + break; + + case SDL_MOUSEMOTION: + pos.x = event.motion.x; + pos.y = event.motion.y; + + m_oldMousePos = pos; + + if (EventButtons (event, pos)) + return true; + if (m_phase == EV_PHASE_BUILD) + { + if (BuildMove (pos, m_keymod, event)) + return true; + } + if (m_phase == EV_PHASE_PLAY) + return true; + break; + + case SDL_MOUSEBUTTONUP: + if ( + event.button.button != SDL_BUTTON_LEFT && + event.button.button != SDL_BUTTON_RIGHT) + break; + + pos.x = event.button.x; + pos.y = event.button.y; + + if (EventButtons (event, pos)) + return true; + if (m_phase == EV_PHASE_BUILD) + return true; + if (m_phase == EV_PHASE_PLAY) + { + if (PlayUp (pos)) + return true; + } + if (m_phase == EV_PHASE_BYE) + { + SDL_Event ev; + ev.type = SDL_QUIT; + SDL_PushEvent (&ev); + } + break; + + case SDL_USEREVENT: + switch (event.user.code) + { + case EV_PHASE_DEMO: + m_demoNumber = 0; + DemoPlayStart (); + break; + + case EV_PHASE_SCHOOL: + m_bSchool = true; + m_bPrivate = false; + if (ChangePhase (EV_PHASE_INFO)) + return true; + break; + + case EV_PHASE_MISSION: + m_bSchool = false; + m_bPrivate = false; + if (m_mission == 0) // première mission ? + { + if (ChangePhase (EV_PHASE_H0MOVIE)) + return true; + } + else + { + if (ChangePhase (EV_PHASE_INFO)) + return true; + } + break; + + case EV_PHASE_PRIVATE: + m_bSchool = false; + m_bPrivate = true; + if (ChangePhase (EV_PHASE_INFO)) + return true; + break; + + case EV_PHASE_INTRO1: + case EV_PHASE_INIT: + case EV_PHASE_HISTORY0: + case EV_PHASE_HISTORY1: + case EV_PHASE_INFO: + case EV_PHASE_PLAY: + case EV_PHASE_READ: + case EV_PHASE_WRITE: + case EV_PHASE_WRITEp: + case EV_PHASE_BUILD: + case EV_PHASE_BUTTON: + case EV_PHASE_TERM: + case EV_PHASE_STOP: + case EV_PHASE_HELP: + case EV_PHASE_MUSIC: + case EV_PHASE_REGION: + case EV_PHASE_SETTINGS: + case EV_PHASE_SETUP: + case EV_PHASE_SETUPp: + case EV_PHASE_PLAYMOVIE: + case EV_PHASE_H0MOVIE: + case EV_PHASE_H1MOVIE: + case EV_PHASE_H2MOVIE: + case EV_PHASE_WINMOVIE: + case EV_PHASE_BYE: + if (ChangePhase (event.user.code)) + return true; + break; + + case EV_PHASE_UNDO: + m_pDecor->UndoBack (); // revient en arrière + break; + + case EV_PREV: + m_pDecor->SetInvincible (false); + m_pDecor->SetSuper (false); + if (m_bPrivate) + { + if (m_private > 0) + { + m_private--; + if (ChangePhase (EV_PHASE_INFO)) + return true; + } + } + else if (m_bSchool) + { + if (m_exercice > 0) + { + m_exercice--; + if (ChangePhase (EV_PHASE_INFO)) + return true; + } + } + else + { + if (m_mission > 0) + { + m_mission--; + if (ChangePhase (EV_PHASE_INFO)) + return true; + } + } + break; + + case EV_NEXT: + m_pDecor->SetInvincible (false); + m_pDecor->SetSuper (false); + if (m_bPrivate) + { + if (m_private < MAX_PRIVATE_MISSIONS - 1) + { + m_private++; + if (ChangePhase (EV_PHASE_INFO)) + return true; + } + } + else if (m_bSchool) + { + if (m_exercice < 99) + { + m_exercice++; + if (ChangePhase (EV_PHASE_INFO)) + return true; + } + } + else + { + if (m_mission < 99) + { + m_mission++; + if (m_maxMission < m_mission) + m_maxMission = m_mission; + if (ChangePhase (EV_PHASE_INFO)) + return true; + } + } + break; + + case EV_DECOR1: + SetState (EV_DECOR1, 1); + SetState (EV_DECOR2, 0); + SetState (EV_DECOR3, 0); + SetState (EV_DECOR4, 0); + SetState (EV_DECOR5, 0); + break; + + case EV_DECOR2: + SetState (EV_DECOR1, 0); + SetState (EV_DECOR2, 1); + SetState (EV_DECOR3, 0); + SetState (EV_DECOR4, 0); + SetState (EV_DECOR5, 0); + break; + + case EV_DECOR3: + SetState (EV_DECOR1, 0); + SetState (EV_DECOR2, 0); + SetState (EV_DECOR3, 1); + SetState (EV_DECOR4, 0); + SetState (EV_DECOR5, 0); + break; + + case EV_DECOR4: + SetState (EV_DECOR1, 0); + SetState (EV_DECOR2, 0); + SetState (EV_DECOR3, 0); + SetState (EV_DECOR4, 1); + SetState (EV_DECOR5, 0); + break; + + case EV_DECOR5: + SetState (EV_DECOR1, 0); + SetState (EV_DECOR2, 0); + SetState (EV_DECOR3, 0); + SetState (EV_DECOR4, 0); + SetState (EV_DECOR5, 1); + break; + + case EV_PHASE_SKILL1: + m_pDecor->SetSkill (0); + SetState (EV_PHASE_SKILL1, true); + SetState (EV_PHASE_SKILL2, false); + break; + case EV_PHASE_SKILL2: + m_pDecor->SetSkill (1); + SetState (EV_PHASE_SKILL1, false); + SetState (EV_PHASE_SKILL2, true); + break; + + case EV_BUTTON0: + case EV_BUTTON1: + case EV_BUTTON2: + case EV_BUTTON3: + case EV_BUTTON4: + case EV_BUTTON5: + case EV_BUTTON6: + case EV_BUTTON7: + case EV_BUTTON8: + case EV_BUTTON9: + case EV_BUTTON10: + case EV_BUTTON11: + case EV_BUTTON12: + case EV_BUTTON13: + case EV_BUTTON14: + case EV_BUTTON15: + case EV_BUTTON16: + case EV_BUTTON17: + case EV_BUTTON18: + case EV_BUTTON19: + case EV_BUTTON20: + case EV_BUTTON21: + case EV_BUTTON22: + case EV_BUTTON23: + case EV_BUTTON24: + case EV_BUTTON25: + case EV_BUTTON26: + case EV_BUTTON27: + case EV_BUTTON28: + case EV_BUTTON29: + case EV_BUTTON30: + case EV_BUTTON31: + case EV_BUTTON32: + case EV_BUTTON33: + case EV_BUTTON34: + case EV_BUTTON35: + case EV_BUTTON36: + case EV_BUTTON37: + case EV_BUTTON38: + case EV_BUTTON39: + ChangeButtons (event.user.code); + break; + + case EV_READ0: + case EV_READ1: + case EV_READ2: + case EV_READ3: + case EV_READ4: + case EV_READ5: + case EV_READ6: + case EV_READ7: + case EV_READ8: + case EV_READ9: + Read (event.user.code); + ChangePhase (EV_PHASE_PLAY); // joue + break; + + case EV_SETUP_EXIT: + case EV_READ_EXIT: + ChangePhase (this->m_pDecor->GetTime () ? EV_PHASE_STOP : EV_PHASE_INFO); + break; + + case EV_WRITE0: + case EV_WRITE1: + case EV_WRITE2: + case EV_WRITE3: + case EV_WRITE4: + case EV_WRITE5: + case EV_WRITE6: + case EV_WRITE7: + case EV_WRITE8: + case EV_WRITE9: + Write (event.user.code); + if (m_phase == EV_PHASE_WRITEp) + { + ChangePhase (EV_PHASE_PLAY); // joue + } + else + { + ChangePhase (EV_PHASE_STOP); // pause + } + break; + + case EV_MOVIE: + StartMovie ("movie/essai.avi"); + ChangePhase (EV_PHASE_INIT); + break; + } + } + + return false; +} + +// Passe les images d'introduction. + +void +CEvent::IntroStep () +{ + m_introTime++; + + if (m_introTime > 20 * 1) + { + if (m_phase == EV_PHASE_INTRO1) + { + ChangePhase (EV_PHASE_INIT); + return; + } + } +} + +void +CEvent::PushUserEvent (Sint32 code, void * data) +{ + SDL_Event event; + + event.type = SDL_USEREVENT; + event.user.code = code; + event.user.data1 = data; + event.user.data2 = nullptr; + + SDL_PushEvent (&event); +} diff --git a/src/event.h b/src/event.h new file mode 100644 index 0000000..0dfd9b0 --- /dev/null +++ b/src/event.h @@ -0,0 +1,284 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include +#include +#include + +#include "button.h" +#include "menu.h" +#include "pixmap.h" +#include "progress.h" + +class CMovie; + +///////////////////////////////////////////////////////////////////////////// + +typedef struct { + Uint32 message; + Sint32 type; + Sint32 iconMenu[20]; + Sint32 x, y; + const char * toolTips[16]; +} Button; + +typedef struct { + Uint32 phase; + char backName[20]; + std::string backWideName; + CPixmap::Mode mode; + Sint32 bCDrom; + Button buttons[MAXBUTTON]; +} Phase; + +typedef struct { + Sint16 majRev; + Sint16 minRev; + Sint16 bSchool; + Sint16 bPrivate; + Sint16 world; + Sint16 skill; + Sint16 reserve1[99]; +} DemoHeader; + +typedef struct { + Sint32 time; + Uint32 message; + Uint32 wParam; // WParam + Uint32 lParam; // LParam +} DemoEvent; + +struct DemoSDLEvent { + Uint32 time; + Uint32 type; + Sint32 scancode; // keysym + Sint32 sym; // keysym + Uint8 button; + Sint32 x; + Sint32 y; +}; + +enum class Language { + undef = -1, + en = 0, + en_US = 1, + fr = 2, + de = 3, + it = 4, + pl = 5, + tr = 6, + pt = 7, + he = 8, + end, +}; + +class CEvent +{ +public: + CEvent (); + ~CEvent (); + + bool IsDemoPlaying (); + Point GetMousePos (); + void + Create (CPixmap * pPixmap, CDecor * pDecor, CSound * pSound, CMovie * pMovie); + void SetFullScreen (bool bFullScreen, double prevScale = 1); + Sint32 GetWorld (); + Sint32 GetPhysicalWorld (); + Sint32 GetImageWorld (); + bool IsHelpHide (); + bool IsBaseMusicAvailable (Sint32 music, const std::string & format); + std::string GetMusicLocation (Sint32 music); + bool LoadBackground (); + bool ChangePhase (Uint32 phase); + bool MovieToStart (); + Uint32 GetPhase (); + void TryInsert (); + + Sint32 GetButtonIndex (Sint32 button); + Sint32 GetState (Sint32 button); + void SetState (Sint32 button, Sint32 state); + bool GetEnable (Sint32 button); + void SetEnable (Sint32 button, bool bEnable); + bool GetHide (Sint32 button); + void SetHide (Sint32 button, bool bHide); + Sint32 GetMenu (Sint32 button); + void SetMenu (Sint32 button, Sint32 menu); + + bool DrawButtons (); + MouseSprites MousePosToSprite (Point pos); + void MouseSprite (Point pos); + void WaitMouse (bool bWait); + void HideMouse (bool bHide); + Point GetLastMousePos (); + bool TreatEvent (const SDL_Event & event); + bool TreatEventBase (const SDL_Event & event); + + void DecorAutoShift (); + + bool StartMovie (const std::string & pFilename); + void StopMovie (); + bool IsMovie (); + + void Read (Sint32 message); + void Write (Sint32 message); + + void SetSpeed (Sint32 speed); + Sint32 GetSpeed (); + bool GetPause (); + bool IsShift (); + + void DemoStep (); + + void IntroStep (); + + void SetWindowSize (Uint8 newScale); + void SetUpdateVersion (const std::string & version); + + bool EventButtons (const SDL_Event & event, Point pos); + bool PlayMove (Point pos); + + static void PushUserEvent (Sint32 code, void * data = nullptr); + +protected: + void DrawTextCenter (const char * text, Sint32 x, Sint32 y, Sint32 font = 0); + bool CreateButtons (Sint32 phase); + bool MouseOnButton (Point pos); + Sint32 SearchPhase (Uint32 phase); + void DecorShift (Sint32 dx, Sint32 dy); + + bool PlayDown (Point pos, const SDL_Event & event); + bool PlayUp (Point pos); + + Language GetStartLanguage (); + Language GetLanguage (); + void SetLanguage (Language lang = Language::undef); + void SetWindowSize (double prevScale, double newScale); + + void ChangeButtons (Sint32 message); + + void BuildFloor (Point cel, Sint32 insIcon); + void BuildWater (Point cel, Sint32 insIcon); + bool + BuildDown (Point pos, Uint16 mod, const SDL_Event * event, bool bMix = true); + bool BuildMove (Point pos, Uint16 mod, const SDL_Event & event); + + void PrivateLibelle (); + bool ReadLibelle (Sint32 world, bool bSchool, bool bHelp); + bool WriteInfo (); + bool ReadInfo (); + + void DemoRecStart (); + void DemoRecStop (); + bool DemoPlayStart (const std::string * demoFile = nullptr); + void DemoPlayStop (); + static void + WinToSDLEvent (Uint32 msg, WParam wParam, LParam lParam, SDL_Event & event); + void DemoRecEvent (const SDL_Event & event); + +protected: + std::vector m_Languages; + std::vector::iterator m_Lang; + std::string m_LangStart; + Sint32 m_speed; + Sint32 m_exercice; + Sint32 m_mission; + Sint32 m_private; + Sint32 m_maxMission; + Uint32 m_phase; + Sint32 m_index; + bool m_bSchool; + bool m_bPrivate; + bool m_bAccessBuild; + CPixmap * m_pPixmap; + CDecor * m_pDecor; + CSound * m_pSound; + CMovie * m_pMovie; + std::string m_movieToStart; + Sint32 m_phaseAfterMovie; + CButton m_buttons[MAXBUTTON]; + Sint32 m_lastFloor[MAXBUTTON]; + Sint32 m_lastObject[MAXBUTTON]; + Sint32 m_lastHome[MAXBUTTON]; + bool m_bRunMovie; + bool m_bBuildModify; + CJauge m_jauges[2]; + CMenu m_menu; + bool m_bMenu; + Point m_menuPos; + Sint32 m_menuNb; + Buttons m_menuButtons[MAXBUTTON]; + Errors m_menuErrors[MAXBUTTON]; + std::unordered_map m_menuTexts; + Sint32 m_menuPerso; + Point m_menuCel; + Point m_oldMousePos; + bool m_bMouseDown; + bool m_bHili; + Sint32 m_fileWorld[10]; + Sint32 m_fileTime[10]; + Point m_posToolTips; + char m_textToolTips[50]; + MouseSprites m_mouseSprite; + bool m_bFillMouse; + bool m_bWaitMouse; + bool m_bHideMouse; + Sint32 m_rankCheat; + Sint32 m_posCheat; + bool m_bMovie; + bool m_bSpeed; + bool m_bHelp; + bool m_bAllMissions; + Sint32 m_scrollSpeed; + Sint32 m_scrollSpeedPrev; + bool m_bPause; + bool m_bShift; + Sint32 m_shiftPhase; + Point m_shiftVector; + Point m_shiftOffset; + char m_libelle[1000]; + Sint32 m_tryPhase; + Sint32 m_tryInsertCount; + Point m_posInfoButton; + Point m_posHelpButton; + bool m_bHiliInfoButton; + bool m_bHiliHelpButton; + bool m_bInfoHelp; + bool m_bDemoRec; + bool m_bDemoPlay; + DemoEvent * m_pDemoBuffer; + std::vector m_pDemoSDLBuffer; + bool m_bStartRecording; + Uint32 m_demoTime; + size_t m_demoIndex; + size_t m_demoEnd; + Sint32 m_demoNumber; + Uint16 m_keymod; + Point m_debugPos; + Sint32 m_introTime; + Sint32 m_updateBlinking; + std::string m_updateVersion; + Uint32 shiftDirection; + bool statDisabled; +}; + +///////////////////////////////////////////////////////////////////////////// diff --git a/src/fifo.cxx b/src/fifo.cxx new file mode 100644 index 0000000..d553767 --- /dev/null +++ b/src/fifo.cxx @@ -0,0 +1,91 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include +#include + +#include "fifo.h" + +// gestion d'une pile classée en valeur croissantes +// typiquement reprend les coordonnées les plus proches +// du but en premier lieu + +CPileTriee::CPileTriee (Sint32 taille) +{ + m_taille = taille; + m_max = m_out = 0; + m_data = (Element *) malloc (sizeof (Element) * taille); +} + +CPileTriee::~CPileTriee () +{ + free (m_data); +} + +Sint32 +CPileTriee::get () +{ + if (m_out == m_max) + return -1; + Sint32 val = m_data[m_out].pos; + m_out++; + if (m_out >= m_taille) + m_out = 0; + return val; +} + +void +CPileTriee::put (Sint32 pos, Sint32 dist) +{ + Sint32 i = m_out; + Sint32 p, d, m; + + while (i != m_max) + { + // le point est-il plus proche que celui-là ? + if (dist < m_data[i].dist) + { + // oui, insert et décale le suivant + p = m_data[i].pos; + d = m_data[i].dist; + + m_data[i].pos = pos; + m_data[i].dist = dist; + + pos = p; + dist = d; + } + i++; + if (i >= m_taille) + i = 0; + } + + // ajoute le point éloigné à la suite + m = m_max + 1; + if (m >= m_taille) + m = 0; + if (m != m_out) + { + m_data[m_max].pos = pos; + m_data[m_max].dist = dist; + + m_max = m; + } +} diff --git a/src/fifo.h b/src/fifo.h new file mode 100644 index 0000000..acac8be --- /dev/null +++ b/src/fifo.h @@ -0,0 +1,48 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +// traitement d'une liste en fifo + +// stucture pour enpiler des positions +// en fonction de leur distance à la cible +typedef struct { + Sint32 pos; + Sint32 dist; +} Element; + +// traitement d'une pile triée + +class CPileTriee +{ +private: + Sint32 m_taille; // nombre de polongs max + Sint32 m_max; // position limite + Sint32 m_out; // position pour reprendre + Element * m_data; // données + +public: + CPileTriee (Sint32 taille); + ~CPileTriee (); + + void put (Sint32 pos, Sint32 dist); + Sint32 get (); +}; diff --git a/src/fix.cxx b/src/fix.cxx new file mode 100644 index 0000000..3230941 --- /dev/null +++ b/src/fix.cxx @@ -0,0 +1,951 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "decor.h" +#include "misc.h" + +// clang-format off +// Cette table indique les quarts de cases contenant de +// l'eau lorsque la valeur est à un. +// 0 1 +// 2 3 +static const char tableSee[14 * 4] = +{ + 0, 0, 0, 0, // 1 + 0, 1, 0, 1, // 2 + 0, 0, 1, 1, // 3 + 1, 0, 1, 0, // 4 + 1, 1, 0, 0, // 5 + 0, 0, 0, 1, // 6 + 0, 0, 1, 0, // 7 + 1, 0, 0, 0, // 8 + 0, 1, 0, 0, // 9 + 0, 1, 1, 1, // 10 + 1, 0, 1, 1, // 11 + 1, 1, 1, 0, // 12 + 1, 1, 0, 1, // 13 + 1, 1, 1, 1, // 14 +}; + +// Cette table indique les quarts de cases contenant de +// la mousse ou de la terre lorsque la valeur est à un. +// 0 1 +// 2 3 +static const char tableDark[13 * 4] = +{ + 1, 1, 1, 1, // 20 + 0, 1, 0, 1, // 21 + 0, 0, 1, 1, // 22 + 1, 0, 1, 0, // 23 + 1, 1, 0, 0, // 24 + 0, 0, 0, 1, // 25 + 0, 0, 1, 0, // 26 + 1, 0, 0, 0, // 27 + 0, 1, 0, 0, // 28 + 1, 1, 1, 0, // 29 + 1, 1, 0, 1, // 30 + 0, 1, 1, 1, // 31 + 1, 0, 1, 1, // 32 +}; +// clang-format on + +// Retourne les bits contenant de l'eau. + +bool +CDecor::GetSeeBits (Point cel, char * pBits, Sint32 index) +{ + Sint32 icon; + + pBits[0] = 0; + pBits[1] = 0; + pBits[2] = 0; + pBits[3] = 0; + + if (cel.x < 0 || cel.x >= MAXCELX || cel.y < 0 || cel.y >= MAXCELY) + return false; + + icon = m_decor[cel.x / 2][cel.y / 2].floorIcon; + + if (index == 0) // eau ? + { + if (icon < 1 || icon > 14) + return true; + icon -= 1; + pBits[0] = tableSee[icon * 4 + 0]; + pBits[1] = tableSee[icon * 4 + 1]; + pBits[2] = tableSee[icon * 4 + 2]; + pBits[3] = tableSee[icon * 4 + 3]; + } + + if (index == 1) // mousse ? + { + if (icon >= 2 && icon <= 14) + return false; // eau ? + if (icon == 66 || icon == 79) // mousse spéciale ? + { + pBits[0] = 1; + pBits[1] = 1; + pBits[2] = 1; + pBits[3] = 1; + return true; + } + if (icon < 20 || icon > 32) + return true; + icon -= 20; + pBits[0] = tableDark[icon * 4 + 0]; + pBits[1] = tableDark[icon * 4 + 1]; + pBits[2] = tableDark[icon * 4 + 2]; + pBits[3] = tableDark[icon * 4 + 3]; + } + + if (index == 2) // terre ? + { + if (icon >= 2 && icon <= 14) + return false; // eau ? + if ( + (icon >= 46 && icon <= 48) || // terre spéciale ? + icon == 71) // terre à fer ? + { + pBits[0] = 1; + pBits[1] = 1; + pBits[2] = 1; + pBits[3] = 1; + return true; + } + if (icon < 33 || icon > 45) + return true; + icon -= 33; + pBits[0] = tableDark[icon * 4 + 0]; + pBits[1] = tableDark[icon * 4 + 1]; + pBits[2] = tableDark[icon * 4 + 2]; + pBits[3] = tableDark[icon * 4 + 3]; + } + + return true; +} + +static void +CopyBits (char * pDst, char * pSrc) +{ + for (Sint32 i = 0; i < 4; i++) + *pDst++ = *pSrc++; +} + +static bool +ChangeBits (char * pDst, char * pSrc) +{ + for (Sint32 i = 0; i < 4; i++) + { + if (*pDst++ != *pSrc++) + return true; + } + return false; +} + +// Retourne l'icône correspondant aux bits d'eaux. + +Sint32 +CDecor::GetSeeIcon (char * pBits, Sint32 index) +{ + Sint32 i; + + if (index == 0) // eau ? + { + for (i = 0; i < 14; i++) + { + if ( + tableSee[i * 4 + 0] == pBits[0] && tableSee[i * 4 + 1] == pBits[1] && + tableSee[i * 4 + 2] == pBits[2] && tableSee[i * 4 + 3] == pBits[3]) + return i + 1; + } + } + + if (index == 1) // mousse ? + { + for (i = 0; i < 13; i++) + { + if ( + tableDark[i * 4 + 0] == pBits[0] && tableDark[i * 4 + 1] == pBits[1] && + tableDark[i * 4 + 2] == pBits[2] && tableDark[i * 4 + 3] == pBits[3]) + return i + 20; + } + } + + if (index == 2) // terre ? + { + for (i = 0; i < 13; i++) + { + if ( + tableDark[i * 4 + 0] == pBits[0] && tableDark[i * 4 + 1] == pBits[1] && + tableDark[i * 4 + 2] == pBits[2] && tableDark[i * 4 + 3] == pBits[3]) + return i + 33; + } + } + + if (pBits[0] == 0 && pBits[1] == 0 && pBits[2] == 0 && pBits[3] == 0) + return 1; // herbe + + return -1; +} + +// Arrange le sol après une modification. + +void +CDecor::ArrangeFloor (Point cel) +{ + Point test; + Sint32 max, index, icon; + char here[4], bits[4], init[4]; + bool bModif = false; + + icon = m_decor[cel.x / 2][cel.y / 2].floorIcon; + + if (icon >= 59 && icon <= 64) + return; // pont ? + + max = 3; + if (icon >= 15 && icon <= 18) // dalle spéciale ? + { + max = 1; // s'occupe que de l'eau ! + } + + for (index = 0; index < max; index++) + { + if (!GetSeeBits (cel, here, index)) + continue; + + test.x = cel.x - 2; // en bas à gauche + test.y = cel.y + 2; + if (GetSeeBits (test, bits, index)) + { + if ( + bits[2] == here[2] && bits[0] != here[2] && bits[1] != here[2] && + bits[3] != here[2]) + { + here[2] = bits[1]; + bModif = true; + } + } + + test.x = cel.x - 2; // en haut à gauche + test.y = cel.y - 2; + if (GetSeeBits (test, bits, index)) + { + if ( + bits[0] == here[0] && bits[1] != here[0] && bits[2] != here[0] && + bits[3] != here[0]) + { + here[0] = bits[3]; + bModif = true; + } + } + + test.x = cel.x + 2; // en haut à droite + test.y = cel.y - 2; + if (GetSeeBits (test, bits, index)) + { + if ( + bits[1] == here[1] && bits[0] != here[1] && bits[2] != here[1] && + bits[3] != here[1]) + { + here[1] = bits[2]; + bModif = true; + } + } + + test.x = cel.x + 2; // en bas à droite + test.y = cel.y + 2; + if (GetSeeBits (test, bits, index)) + { + if ( + bits[3] == here[3] && bits[0] != here[3] && bits[1] != here[3] && + bits[2] != here[3]) + { + here[3] = bits[0]; + bModif = true; + } + } + + if (bModif) + { + icon = GetSeeIcon (here, index); + if (icon != -1) + m_decor[cel.x / 2][cel.y / 2].floorIcon = icon; + } + + test.x = cel.x - 2; // à gauche + test.y = cel.y; + if (GetSeeBits (test, bits, index)) + { + CopyBits (init, bits); + bits[1] = here[0] ? 1 : 0; + bits[3] = here[2] ? 1 : 0; + icon = GetSeeIcon (bits, index); + if (ChangeBits (init, bits) && icon != -1) + m_decor[test.x / 2][test.y / 2].floorIcon = icon; + } + + test.x = cel.x - 2; // en haut à gauche + test.y = cel.y - 2; + if (GetSeeBits (test, bits, index)) + { + CopyBits (init, bits); + bits[3] = here[0] ? 1 : 0; + icon = GetSeeIcon (bits, index); + if (ChangeBits (init, bits) && icon != -1) + m_decor[test.x / 2][test.y / 2].floorIcon = icon; + } + + test.x = cel.x; // en haut + test.y = cel.y - 2; + if (GetSeeBits (test, bits, index)) + { + CopyBits (init, bits); + bits[2] = here[0] ? 1 : 0; + bits[3] = here[1] ? 1 : 0; + icon = GetSeeIcon (bits, index); + if (ChangeBits (init, bits) && icon != -1) + m_decor[test.x / 2][test.y / 2].floorIcon = icon; + } + + test.x = cel.x + 2; // en haut à droite + test.y = cel.y - 2; + if (GetSeeBits (test, bits, index)) + { + CopyBits (init, bits); + bits[2] = here[1] ? 1 : 0; + icon = GetSeeIcon (bits, index); + if (ChangeBits (init, bits) && icon != -1) + m_decor[test.x / 2][test.y / 2].floorIcon = icon; + } + + test.x = cel.x + 2; // à droite + test.y = cel.y; + if (GetSeeBits (test, bits, index)) + { + CopyBits (init, bits); + bits[0] = here[1] ? 1 : 0; + bits[2] = here[3] ? 1 : 0; + icon = GetSeeIcon (bits, index); + if (ChangeBits (init, bits) && icon != -1) + m_decor[test.x / 2][test.y / 2].floorIcon = icon; + } + + test.x = cel.x + 2; // en bas à droite + test.y = cel.y + 2; + if (GetSeeBits (test, bits, index)) + { + CopyBits (init, bits); + bits[0] = here[3] ? 1 : 0; + icon = GetSeeIcon (bits, index); + if (ChangeBits (init, bits) && icon != -1) + m_decor[test.x / 2][test.y / 2].floorIcon = icon; + } + + test.x = cel.x; // en bas + test.y = cel.y + 2; + if (GetSeeBits (test, bits, index)) + { + CopyBits (init, bits); + bits[0] = here[2] ? 1 : 0; + bits[1] = here[3] ? 1 : 0; + icon = GetSeeIcon (bits, index); + if (ChangeBits (init, bits) && icon != -1) + m_decor[test.x / 2][test.y / 2].floorIcon = icon; + } + + test.x = cel.x - 2; // en bas à gauche + test.y = cel.y + 2; + if (GetSeeBits (test, bits, index)) + { + CopyBits (init, bits); + bits[1] = here[2] ? 1 : 0; + icon = GetSeeIcon (bits, index); + if (ChangeBits (init, bits) && icon != -1) + m_decor[test.x / 2][test.y / 2].floorIcon = icon; + } + } +} + +// clang-format off +// Cette table donne les directions dans l'ordre +// est-sud-ouest-nord pour les murs. +static const char tableMur[5 * 15] = +{ + 20, 1, 0, 1, 0, + 21, 0, 1, 0, 1, + 22, 1, 1, 0, 0, + 23, 0, 1, 1, 0, + 24, 0, 0, 1, 1, + 25, 1, 0, 0, 1, + 26, 1, 1, 1, 1, + + 26, 0, 1, 1, 1, + 26, 1, 0, 1, 1, + 26, 1, 1, 0, 1, + 26, 1, 1, 1, 0, + + 20, 1, 0, 0, 0, + 20, 0, 0, 1, 0, + 21, 0, 1, 0, 0, + 21, 0, 0, 0, 1, +}; + +static const Sint16 tableMurDir[4 * 2] = +{ + +2, 0, // est + 0, +2, // sur + -2, 0, // ouest + 0, -2, // nord +}; +// clang-format on + +// Arrange un mur en fonction des autres murs dans toutes +// les directions. +// index=0 si mur (20..26) +// index=1 si palissade (65..71) +// index=2 si barrière (106..112) + +void +CDecor::ArrangeMur (Point cel, Sint32 & icon, Sint32 index) +{ + Sint32 i, x, y, channel; + Sint32 first, last, matiere; + Sint32 icons[4]; + char murs[4]; + + if (index == 0) + { + first = 20; + last = 26; + matiere = 44; // pierres + } + if (index == 1) + { + first = 65; + last = 71; + matiere = 36; // planches + } + if (index == 2) + { + first = 106; + last = 112; + matiere = 36; // planches + } + + for (i = 0; i < 4; i++) + { + x = cel.x + tableMurDir[i * 2 + 0]; + y = cel.y + tableMurDir[i * 2 + 1]; + + if (IsValid (GetCel (x, y))) + { + icons[i] = m_decor[x / 2][y / 2].objectIcon; + if (icons[i] == matiere) // pierres/planches ? + MoveGetObject (GetCel (x, y), channel, icons[i]); + + if (icons[i] < first || icons[i] > last) + icons[i] = -1; + } + else + icons[i] = -1; + } + + for (i = 0; i < 4; i++) + { + if (icons[i] == -1) + murs[i] = 0; + else + murs[i] = tableMur[(icons[i] - first) * 5 + 1 + ((i + 2) % 4)]; + } + + for (i = 0; i < 15; i++) + { + if ( + murs[0] == tableMur[i * 5 + 1] && murs[1] == tableMur[i * 5 + 2] && + murs[2] == tableMur[i * 5 + 3] && murs[3] == tableMur[i * 5 + 4]) + { + icon = tableMur[i * 5 + 0]; + icon += first - 20; + return; + } + } + + icon = -1; +} + +// Arrange les objets avant une construction. + +void +CDecor::ArrangeBuild (Point cel, Sint32 & channel, Sint32 & icon) +{ + Sint32 index, i, x, y; + Sint32 first, last, matiere; + Sint32 oldChannel, oldIcon; + + for (index = 0; index < 3; index++) + { + if (index == 0) + { + first = 20; + last = 26; + matiere = 44; // pierres + } + if (index == 1) + { + first = 65; + last = 71; + matiere = 36; // planches + } + if (index == 2) + { + first = 106; + last = 112; + matiere = 36; // planches + } + + // Rien à faire si pas mur. + if (channel != CHOBJECT || icon != last) + continue; + + oldChannel = m_decor[cel.x / 2][cel.y / 2].objectChannel; + oldIcon = m_decor[cel.x / 2][cel.y / 2].objectIcon; + + m_decor[cel.x / 2][cel.y / 2].objectChannel = channel; + m_decor[cel.x / 2][cel.y / 2].objectIcon = icon; + + for (i = 0; i < 4; i++) + { + x = cel.x + tableMurDir[i * 2 + 0]; + y = cel.y + tableMurDir[i * 2 + 1]; + + if (IsValid (GetCel (x, y))) + { + icon = m_decor[x / 2][y / 2].objectIcon; + if (icon == matiere) // pierres/planches ? + MoveGetObject (GetCel (x, y), channel, icon); + + if (icon >= first && icon <= last) + { + ArrangeMur (GetCel (x, y), icon, index); + + if (icon != -1) + { + if (!MovePutObject (GetCel (x, y), channel, icon)) + { + m_decor[x / 2][y / 2].objectChannel = channel; + m_decor[x / 2][y / 2].objectIcon = icon; + } + } + } + } + } + + m_decor[cel.x / 2][cel.y / 2].objectChannel = oldChannel; + m_decor[cel.x / 2][cel.y / 2].objectIcon = oldIcon; + + ArrangeMur (cel, icon, index); + if (icon == -1) + icon = last; + } +} + +// Arrange les objets après une modification. + +void +CDecor::ArrangeObject (Point cel) +{ + Sint32 channel, icon; + Sint32 first, last; + Sint32 index, i, j, k, x, y; + Point vector, test, pos; + bool bTour; + + for (index = 0; index < 3; index++) + { + if (index == 0) + { + first = 20; // murs + last = 26; + } + if (index == 1) + { + first = 65; // palissades + last = 71; + } + if (index == 2) + { + first = 106; // barrière + last = 112; + } + + for (i = 0; i < 4; i++) + { + x = cel.x + tableMurDir[i * 2 + 0]; + y = cel.y + tableMurDir[i * 2 + 1]; + + if (IsValid (GetCel (x, y))) + { + icon = m_decor[x / 2][y / 2].objectIcon; + if (icon >= first && icon <= last) + { + ArrangeMur (GetCel (x, y), icon, index); + + if (icon != -1) + { + m_decor[x / 2][y / 2].objectChannel = CHOBJECT; + m_decor[x / 2][y / 2].objectIcon = icon; + } + } + } + } + + if (m_decor[cel.x / 2][cel.y / 2].objectIcon == last) + { + ArrangeMur (cel, icon, index); + if (icon == -1) + icon = last; + + m_decor[cel.x / 2][cel.y / 2].objectChannel = CHOBJECT; + m_decor[cel.x / 2][cel.y / 2].objectIcon = icon; + } + } + + if ( + g_restoreBugs && + (m_decor[cel.x / 2][cel.y / 2].objectIcon != 27 && // not a tower? + m_decor[cel.x / 2][cel.y / 2].objectIcon != -1)) + return; + + // Arrange les rayons entre les tours. + for (i = 0; i < 4; i++) + { + vector = GetVector (i * 2 * 16); + test = cel; + + bTour = false; + j = 0; + while (true) + { + test.x += vector.x * 2; + test.y += vector.y * 2; + + if (m_decor[test.x / 2][test.y / 2].objectIcon == 27) // tour ? + { + bTour = true; + break; + } + + if ( + m_decor[test.x / 2][test.y / 2].objectIcon != -1 && + m_decor[test.x / 2][test.y / 2].objectIcon != 10001 - i % 2) + break; + + j++; + if (j >= 2 + 1) + break; + } + + if (m_decor[cel.x / 2][cel.y / 2].objectIcon != 27) // pas tour ? + bTour = false; + + test = cel; + for (k = 0; k < j; k++) + { + test.x += vector.x * 2; + test.y += vector.y * 2; + + if (bTour) + { + channel = CHOBJECT; + icon = 10001 - i % 2; // rayon e-o (10001) ou n-s (10000) + } + else + { + channel = -1; + icon = -1; + } + m_decor[test.x / 2][test.y / 2].objectChannel = channel; + m_decor[test.x / 2][test.y / 2].objectIcon = icon; + + if (!m_bBuild && bTour) + { + if (MoveCreate ( + test, -1, false, CHOBJECT, -1, -1, -1, 9999, 1, 0, true)) + { + MoveAddIcons (test, 5 - i % 2, true); // éclairs + } + + pos = ConvCelToPos (test); + m_pSound->PlayImage (SOUND_RAYON1, pos); + } + + if (!m_bBuild && !bTour) + MoveFinish (test); + } + } +} + +// Test s'il faut remplir le sol ici. + +bool +CDecor::ArrangeFillTestFloor (Point cel1, Point cel2) +{ + Point cel; + Sint32 icon1, icon2; + + icon1 = m_fillSearchIcon; + icon2 = m_fillSearchIcon; + + if ( + m_fillPutChannel == CHFLOOR && m_fillPutIcon == 1 && // met de l'herbe.. + m_fillSearchIcon == 14) // ..sur de l'eau ? + { + icon1 = 2; + icon2 = 14; // eau & rives + } + + if ( + m_fillPutChannel == CHFLOOR && m_fillPutIcon == 14 && // met de l'eau.. + m_fillSearchIcon == 1) // ..sur de l'herbe ? + { + icon1 = 1; + icon2 = 13; // herbe & rives + } + + for (cel.x = cel1.x; cel.x <= cel2.x; cel.x += 2) + { + for (cel.y = cel1.y; cel.y <= cel2.y; cel.y += 2) + { + if (!IsValid (cel)) + continue; + + if ( + m_decor[cel.x / 2][cel.y / 2].floorChannel != m_fillSearchChannel || + m_decor[cel.x / 2][cel.y / 2].floorIcon < icon1 || + m_decor[cel.x / 2][cel.y / 2].floorIcon > icon2) + return false; + + if ( + m_fillPutChannel == CHFLOOR && m_fillPutIcon == 14 && // met de l'eau ? + m_decor[cel.x / 2][cel.y / 2].objectIcon != -1) + return false; + } + } + + if ( + m_fillPutChannel == CHFLOOR && m_fillPutIcon == 14 && // met de l'eau ? + IsBlupiHereEx (cel1, cel2, -1, false)) + return false; + + return true; +} + +// Test s'il faut remplir ici. + +bool +CDecor::ArrangeFillTest (Point pos) +{ + Point cel1, cel2; + + if (m_pFillMap[(pos.x / 2) + (pos.y / 2) * (MAXCELX / 2)] == 1) + return false; + + if (m_bFillFloor) + { + cel1.x = pos.x - 2; + cel1.y = pos.y - 2; + cel2.x = pos.x + 3; + cel2.y = pos.y + 3; + return ArrangeFillTestFloor (cel1, cel2); + } + else + { + if ( + m_decor[pos.x / 2][pos.y / 2].objectChannel == m_fillSearchChannel && + m_decor[pos.x / 2][pos.y / 2].objectIcon == m_fillSearchIcon && + !IsBlupiHereEx ( + GetCel (pos.x + 0, pos.y + 0), GetCel (pos.x + 1, pos.y + 1), -1, + false)) + { + if ( + m_decor[pos.x / 2][pos.y / 2].floorChannel == CHFLOOR && + m_decor[pos.x / 2][pos.y / 2].floorIcon >= 2 && + m_decor[pos.x / 2][pos.y / 2].floorIcon <= 14) // rive ou eau ? + return false; + + return true; + } + } + + return false; +} + +// Modifie le décor lors d'un remplissage. + +void +CDecor::ArrangeFillPut (Point pos, Sint32 channel, Sint32 icon) +{ + if (m_bFillFloor) + { + PutFloor (pos, channel, icon); + ArrangeFloor (pos); + } + else + { + if (icon >= 0 && icon <= 5) // plantes ? + icon = Random (0, 5); + if (icon >= 6 && icon <= 11) // arbres ? + icon = Random (6, 11); + if (icon >= 37 && icon <= 43) // rochers ? + icon = Random (37, 43); + PutObject (pos, channel, icon); + ArrangeObject (pos); + } +} + +// Rempli un sol à partir d'une position donnée. + +void +CDecor::ArrangeFillSearch (Point pos) +{ + Sint32 startX, endX; + + // Cherche la borne gauche. + startX = pos.x; + endX = pos.x; + while (pos.x > 0 && ArrangeFillTest (pos)) + pos.x -= 2; + startX = pos.x + 2; + + // Cherche la borne droite. + pos.x = endX; + while (pos.x < MAXCELX - 2 && ArrangeFillTest (pos)) + pos.x += 2; + endX = pos.x - 2; + + // Rempli toute la ligne trouvée. + pos.x = startX; + while (pos.x <= endX) + { + m_pFillMap[(pos.x / 2) + (pos.y / 2) * (MAXCELX / 2)] = 1; + pos.x += 2; + } + + // Cherche la ligne au-dessus. + if (pos.y > 0) + { + pos.y -= 2; + pos.x = startX; + while (pos.x <= endX) + { + while (pos.x <= endX && !ArrangeFillTest (pos)) + pos.x += 2; + if (pos.x > endX) + break; + + if (ArrangeFillTest (pos)) + { + ArrangeFillSearch (pos); // appel récursif + } + + while (pos.x <= endX && ArrangeFillTest (pos)) + pos.x += 2; + } + pos.y += 2; + } + + // Cherche la ligne au-dessous. + if (pos.y < MAXCELY - 2) + { + pos.y += 2; + pos.x = startX; + while (pos.x <= endX) + { + while (pos.x <= endX && !ArrangeFillTest (pos)) + pos.x += 2; + if (pos.x > endX) + break; + + if (ArrangeFillTest (pos)) + { + ArrangeFillSearch (pos); // appel récursif + } + + while (pos.x <= endX && ArrangeFillTest (pos)) + pos.x += 2; + } + } +} + +// Rempli un sol à partir d'une position donnée. + +void +CDecor::ArrangeFill (Point pos, Sint32 channel, Sint32 icon, bool bFloor) +{ + m_bFillFloor = bFloor; + + pos.x = (pos.x / 2) * 2; + pos.y = (pos.y / 2) * 2; + + m_fillPutChannel = channel; + m_fillPutIcon = icon; + + if (bFloor) + GetFloor (pos, m_fillSearchChannel, m_fillSearchIcon); + else + GetObject (pos, m_fillSearchChannel, m_fillSearchIcon); + + m_pFillMap = (char *) malloc (MAXCELX * MAXCELY * sizeof (char) / 4); + if (m_pFillMap == nullptr) + return; + memset (m_pFillMap, 0, MAXCELX * MAXCELY * sizeof (char) / 4); + + ArrangeFillSearch (pos); + + for (pos.x = 0; pos.x < MAXCELX; pos.x += 2) + { + for (pos.y = 0; pos.y < MAXCELY; pos.y += 2) + { + if (m_pFillMap[(pos.x / 2) + (pos.y / 2) * (MAXCELX / 2)] == 1) + ArrangeFillPut (pos, channel, icon); + } + } + + free (m_pFillMap); +} + +// Supprime tous les personnages bloqués dans des murs +// ou debout sur l'eau. + +void +CDecor::ArrangeBlupi () +{ + Sint32 rank; + + for (rank = 0; rank < MAXBLUPI; rank++) + { + if (m_blupi[rank].bExist) + { + if (!IsFreeCel (m_blupi[rank].cel, rank)) + m_blupi[rank].bExist = false; + } + } +} diff --git a/src/fog.cxx b/src/fog.cxx new file mode 100644 index 0000000..8e6dd2f --- /dev/null +++ b/src/fog.cxx @@ -0,0 +1,156 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "decor.h" + +// clang-format off +// Cette table indique les quarts de cases contenant du +// brouillard lorsque la valeur est à un. +// 0 1 +// 2 3 +static char tableFog[15 * 4] = +{ + 1, 1, 1, 0, // 0 + 1, 1, 0, 0, // 1 + 1, 1, 0, 1, // 2 + 1, 0, 1, 0, // 3 + 1, 1, 1, 1, // 4 + 0, 1, 0, 1, // 5 + 1, 0, 1, 1, // 6 + 0, 0, 1, 1, // 7 + 0, 1, 1, 1, // 8 + 0, 0, 0, 1, // 9 + 0, 0, 1, 0, // 10 + 1, 0, 0, 1, // 11 + 0, 1, 0, 0, // 12 + 1, 0, 0, 0, // 13 + 0, 1, 1, 0, // 14 +}; +// clang-format on + +// Retourne les bits contenant du brouillard. + +bool +GetFogBits (Sint32 icon, char * pBits) +{ + pBits[0] = 0; + pBits[1] = 0; + pBits[2] = 0; + pBits[3] = 0; + + if (icon < 0 || icon >= 15) + return true; + + pBits[0] = tableFog[icon * 4 + 0]; + pBits[1] = tableFog[icon * 4 + 1]; + pBits[2] = tableFog[icon * 4 + 2]; + pBits[3] = tableFog[icon * 4 + 3]; + + return true; +} + +// Retourne l'icône correspondant aux bits de brouillard. + +Sint32 +GetFogIcon (char * pBits) +{ + Sint32 i; + + for (i = 0; i < 15; i++) + { + if ( + tableFog[i * 4 + 0] == pBits[0] && tableFog[i * 4 + 1] == pBits[1] && + tableFog[i * 4 + 2] == pBits[2] && tableFog[i * 4 + 3] == pBits[3]) + return i; + } + + return -1; +} + +// Table donnant la "vision" d'un blupi dans le +// brouillard. +// clang-format off +static Sint8 table_fog[17 * 17] = +{ + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 1, -1, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 1, -1, -1, -1, 5, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 1, -1, -1, -1, -1, -1, 5, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 1, -1, -1, -1, -1, -1, -1, -1, 5, 4, 4, 4, 4, 4, + 4, 4, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 4, 4, 4, 4, + 4, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 4, 4, 4, + 4, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 4, 4, + 4, 4, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, 4, + 4, 4, 4, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, 4, 4, + 4, 4, 4, 4, 4, 3, -1, -1, -1, -1, -1, -1, -1, 7, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 3, -1, -1, -1, -1, -1, 7, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 3, -1, -1, -1, 7, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 3, -1, 7, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, +}; +// clang-format on + +// Ecarte le brouillard autour d'un blupi. + +void +CDecor::BlupiPushFog (Sint32 rank) +{ + Sint32 x, y, i; + Point cel; + char cBits[4]; + char nBits[4]; + + if (m_blupi[rank].perso != 0 && m_blupi[rank].perso != 8) + return; + + for (y = 0; y < 17; y++) + { + for (x = 0; x < 17; x++) + { + if (x % 2 != y % 2) + continue; + if (table_fog[x + y * 17] == FOGHIDE) + continue; + + cel.x = (x + ((m_blupi[rank].cel.x + 1) / 4) * 2 - 8) * 2; + cel.y = (y + ((m_blupi[rank].cel.y + 1) / 4) * 2 - 8) * 2; + + // Ne pas utiliser IsValid pour permettre d'aller + // jusqu'au bord ! + if (cel.x >= 0 && cel.x < MAXCELX && cel.y >= 0 && cel.y < MAXCELX) + { + if (m_decor[cel.x / 2][cel.y / 2].fog != -1) + { + GetFogBits (m_decor[cel.x / 2][cel.y / 2].fog, cBits); + GetFogBits (table_fog[x + y * 17], nBits); + + for (i = 0; i < 4; i++) + { + nBits[i] &= cBits[i]; // "ou" visibilité + } + + m_decor[cel.x / 2][cel.y / 2].fog = GetFogIcon (nBits); + } + } + } + } +} diff --git a/src/gettext.h b/src/gettext.h new file mode 100644 index 0000000..6a32e04 --- /dev/null +++ b/src/gettext.h @@ -0,0 +1,24 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 2017, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include + +#define translate(msgid) msgid diff --git a/src/json/json.hpp b/src/json/json.hpp new file mode 100644 index 0000000..6dfc183 --- /dev/null +++ b/src/json/json.hpp @@ -0,0 +1,13003 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 2.1.1 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +Copyright (c) 2013-2017 Niels Lohmann . + +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 NLOHMANN_JSON_HPP +#define NLOHMANN_JSON_HPP + +#include // all_of, copy, fill, find, for_each, none_of, remove, reverse, transform +#include // array +#include // assert +#include // isdigit +#include // and, not, or +#include // isfinite, labs, ldexp, signbit +#include // nullptr_t, ptrdiff_t, size_t +#include // int64_t, uint64_t +#include // abort, strtod, strtof, strtold, strtoul, strtoll, strtoull +#include // strlen +#include // forward_list +#include // function, hash, less +#include // initializer_list +#include // setw +#include // istream, ostream +#include // advance, begin, back_inserter, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator +#include // numeric_limits +#include // locale +#include // map +#include // addressof, allocator, allocator_traits, unique_ptr +#include // accumulate +#include // stringstream +#include // domain_error, invalid_argument, out_of_range +#include // getline, stoi, string, to_string +#include // add_pointer, conditional, decay, enable_if, false_type, integral_constant, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_default_constructible, is_enum, is_floating_point, is_integral, is_nothrow_move_assignable, is_nothrow_move_constructible, is_pointer, is_reference, is_same, is_scalar, is_signed, remove_const, remove_cv, remove_pointer, remove_reference, true_type, underlying_type +#include // declval, forward, make_pair, move, pair, swap +#include // vector + +// exclude unsupported compilers +#if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#elif defined(__GNUC__) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define JSON_DEPRECATED __declspec(deprecated) +#else + #define JSON_DEPRECATED +#endif + +// allow to disable exceptions +#if not defined(JSON_NOEXCEPTION) || defined(__EXCEPTIONS) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) +#else + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) +#endif + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ + +/*! +@brief unnamed namespace with internal helper functions + +This namespace collects some functions that could not be defined inside the +@ref basic_json class. + +@since version 2.1.0 +*/ +namespace detail +{ +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + discarded ///< discarded by the the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string +- furthermore, each type is not smaller than itself + +@since version 1.0.0 +*/ +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + static constexpr std::array order = {{ + 0, // null + 3, // object + 4, // array + 5, // string + 1, // boolean + 2, // integer + 2, // unsigned + 2, // float + } + }; + + // discarded values are not comparable + if (lhs == value_t::discarded or rhs == value_t::discarded) + { + return false; + } + + return order[static_cast(lhs)] < + order[static_cast(rhs)]; +} + + +///////////// +// helpers // +///////////// + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// taken from http://stackoverflow.com/a/26936864/266378 +template +using is_unscoped_enum = + std::integral_constant::value and + std::is_enum::value>; + +/* +Implementation of two C++17 constructs: conjunction, negation. This is needed +to avoid evaluating all the traits in a condition + +For example: not std::is_same::value and has_value_type::value +will not compile when T = void (on MSVC at least). Whereas +conjunction>, has_value_type>::value will +stop evaluating if negation<...>::value == false + +Please note that those constructs must be used with caution, since symbols can +become very long quickly (which can slow down compilation and cause MSVC +internal compiler errors). Only use it when you have to (see example ahead). +*/ +template struct conjunction : std::true_type {}; +template struct conjunction : B1 {}; +template +struct conjunction : std::conditional, B1>::type {}; + +template struct negation : std::integral_constant < bool, !B::value > {}; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + + +////////////////// +// constructors // +////////////////// + +template struct external_constructor; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept + { + j.m_type = value_t::boolean; + j.m_value = b; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) + { + j.m_type = value_t::string; + j.m_value = s; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept + { + // replace infinity and NAN by null + if (not std::isfinite(val)) + { + j = BasicJsonType{}; + } + else + { + j.m_type = value_t::number_float; + j.m_value = val; + } + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept + { + j.m_type = value_t::number_unsigned; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept + { + j.m_type = value_t::number_integer; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) + { + j.m_type = value_t::array; + j.m_value = arr; + j.assert_invariant(); + } + + template::value, + int> = 0> + static void construct(BasicJsonType& j, const CompatibleArrayType& arr) + { + using std::begin; + using std::end; + j.m_type = value_t::array; + j.m_value.array = j.template create(begin(arr), end(arr)); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) + { + j.m_type = value_t::object; + j.m_value = obj; + j.assert_invariant(); + } + + template::value, + int> = 0> + static void construct(BasicJsonType& j, const CompatibleObjectType& obj) + { + using std::begin; + using std::end; + + j.m_type = value_t::object; + j.m_value.object = j.template create(begin(obj), end(obj)); + j.assert_invariant(); + } +}; + + +//////////////////////// +// has_/is_ functions // +//////////////////////// + +/*! +@brief Helper to determine whether there's a key_type for T. + +This helper is used to tell associative containers apart from other containers +such as sequence containers. For instance, `std::map` passes the test as it +contains a `mapped_type`, whereas `std::vector` fails the test. + +@sa http://stackoverflow.com/a/7728728/266378 +@since version 1.0.0, overworked in version 2.0.6 +*/ +#define NLOHMANN_JSON_HAS_HELPER(type) \ + template struct has_##type { \ + private: \ + template \ + static int detect(U &&); \ + static void detect(...); \ + public: \ + static constexpr bool value = \ + std::is_integral()))>::value; \ + } + +NLOHMANN_JSON_HAS_HELPER(mapped_type); +NLOHMANN_JSON_HAS_HELPER(key_type); +NLOHMANN_JSON_HAS_HELPER(value_type); +NLOHMANN_JSON_HAS_HELPER(iterator); + +#undef NLOHMANN_JSON_HAS_HELPER + + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl +{ + static constexpr auto value = + std::is_constructible::value and + std::is_constructible::value; +}; + +template +struct is_compatible_object_type +{ + static auto constexpr value = is_compatible_object_type_impl < + conjunction>, + has_mapped_type, + has_key_type>::value, + typename BasicJsonType::object_t, CompatibleObjectType >::value; +}; + +template +struct is_basic_json_nested_type +{ + static auto constexpr value = std::is_same::value or + std::is_same::value or + std::is_same::value or + std::is_same::value or + std::is_same::value; +}; + +template +struct is_compatible_array_type +{ + static auto constexpr value = + conjunction>, + negation>, + negation>, + negation>, + has_value_type, + has_iterator>::value; +}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + std::is_constructible::value and + CompatibleLimits::is_integer and + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type +{ + static constexpr auto value = + is_compatible_integer_type_impl < + std::is_integral::value and + not std::is_same::value, + RealIntegerType, CompatibleNumberIntegerType > ::value; +}; + + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json +{ + private: + // also check the return type of from_json + template::from_json( + std::declval(), std::declval()))>::value>> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json +{ + private: + template < + typename U, + typename = enable_if_t::from_json(std::declval()))>::value >> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +template +struct has_to_json +{ + private: + template::to_json( + std::declval(), std::declval()))> + static int detect(U&&); + static void detect(...); + + public: + static constexpr bool value = std::is_integral>()))>::value; +}; + + +///////////// +// to_json // +///////////// + +template::value, int> = 0> +void to_json(BasicJsonType& j, T b) noexcept +{ + external_constructor::construct(j, b); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleString& s) +{ + external_constructor::construct(j, s); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, FloatType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template < + typename BasicJsonType, typename CompatibleNumberUnsignedType, + enable_if_t::value, int> = 0 > +void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template < + typename BasicJsonType, typename CompatibleNumberIntegerType, + enable_if_t::value, int> = 0 > +void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, UnscopedEnumType e) noexcept +{ + external_constructor::construct(j, e); +} + +template < + typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < + is_compatible_array_type::value or + std::is_same::value, + int > = 0 > +void to_json(BasicJsonType& j, const CompatibleArrayType& arr) +{ + external_constructor::construct(j, arr); +} + +template < + typename BasicJsonType, typename CompatibleObjectType, + enable_if_t::value, + int> = 0 > +void to_json(BasicJsonType& j, const CompatibleObjectType& arr) +{ + external_constructor::construct(j, arr); +} + + +/////////////// +// from_json // +/////////////// + +// overloads for basic_json template parameters +template::value and + not std::is_same::value, + int> = 0> +void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast( + *j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast( + *j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast( + *j.template get_ptr()); + break; + } + default: + { + JSON_THROW( + std::domain_error("type must be number, but is " + j.type_name())); + } + } +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) +{ + if (not j.is_boolean()) + { + JSON_THROW(std::domain_error("type must be boolean, but is " + j.type_name())); + } + b = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) +{ + if (not j.is_string()) + { + JSON_THROW(std::domain_error("type must be string, but is " + j.type_name())); + } + s = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) +{ + get_arithmetic_value(j, val); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, UnscopedEnumType& e) +{ + typename std::underlying_type::type val; + get_arithmetic_value(j, val); + e = static_cast(val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) +{ + if (not j.is_array()) + { + JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); + } + arr = *j.template get_ptr(); +} + +// forward_list doesn't have an insert method +template +void from_json(const BasicJsonType& j, std::forward_list& l) +{ + // do not perform the check when user wants to retrieve jsons + // (except when it's null.. ?) + if (j.is_null()) + { + JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); + } + if (not std::is_same::value) + { + if (not j.is_array()) + { + JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); + } + } + for (auto it = j.rbegin(), end = j.rend(); it != end; ++it) + { + l.push_front(it->template get()); + } +} + +template +void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0>) +{ + using std::begin; + using std::end; + + std::transform(j.begin(), j.end(), + std::inserter(arr, end(arr)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); +} + +template +auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1>) +-> decltype( + arr.reserve(std::declval()), + void()) +{ + using std::begin; + using std::end; + + arr.reserve(j.size()); + std::transform( + j.begin(), j.end(), std::inserter(arr, end(arr)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); +} + +template::value and + not std::is_same::value, int> = 0> +void from_json(const BasicJsonType& j, CompatibleArrayType& arr) +{ + if (j.is_null()) + { + JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); + } + + // when T == BasicJsonType, do not check if value_t is correct + if (not std::is_same::value) + { + if (not j.is_array()) + { + JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); + } + } + from_json_array_impl(j, arr, priority_tag<1> {}); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, CompatibleObjectType& obj) +{ + if (not j.is_object()) + { + JSON_THROW(std::domain_error("type must be object, but is " + j.type_name())); + } + + auto inner_object = j.template get_ptr(); + using std::begin; + using std::end; + // we could avoid the assignment, but this might require a for loop, which + // might be less efficient than the container constructor for some + // containers (would it?) + obj = CompatibleObjectType(begin(*inner_object), end(*inner_object)); +} + +// overload for arithmetic types, not chosen for basic_json template arguments +// (BooleanType, etc..); note: Is it really necessary to provide explicit +// overloads for boolean_t etc. in case of a custom BooleanType which is not +// an arithmetic type? +template::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value, + int> = 0> +void from_json(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::boolean: + { + val = static_cast(*j.template get_ptr()); + break; + } + default: + { + JSON_THROW(std::domain_error("type must be number, but is " + j.type_name())); + } + } +} + +struct to_json_fn +{ + private: + template + auto call(BasicJsonType& j, T&& val, priority_tag<1>) const noexcept(noexcept(to_json(j, std::forward(val)))) + -> decltype(to_json(j, std::forward(val)), void()) + { + return to_json(j, std::forward(val)); + } + + template + void call(BasicJsonType&, T&&, priority_tag<0>) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, + "could not find to_json() method in T's namespace"); + } + + public: + template + void operator()(BasicJsonType& j, T&& val) const + noexcept(noexcept(std::declval().call(j, std::forward(val), priority_tag<1> {}))) + { + return call(j, std::forward(val), priority_tag<1> {}); + } +}; + +struct from_json_fn +{ + private: + template + auto call(const BasicJsonType& j, T& val, priority_tag<1>) const + noexcept(noexcept(from_json(j, val))) + -> decltype(from_json(j, val), void()) + { + return from_json(j, val); + } + + template + void call(const BasicJsonType&, T&, priority_tag<0>) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, + "could not find from_json() method in T's namespace"); + } + + public: + template + void operator()(const BasicJsonType& j, T& val) const + noexcept(noexcept(std::declval().call(j, val, priority_tag<1> {}))) + { + return call(j, val, priority_tag<1> {}); + } +}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} // namespace detail + + +/// namespace to hold default `to_json` / `from_json` functions +namespace +{ +constexpr const auto& to_json = detail::static_const::value; +constexpr const auto& from_json = detail::static_const::value; +} + + +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer +{ + /*! + @brief convert a JSON value to any value type + + This function is usually called by the `get()` function of the + @ref basic_json class (either explicit or via conversion operators). + + @param[in] j JSON value to read from + @param[in,out] val value to write to + */ + template + static void from_json(BasicJsonType&& j, ValueType& val) noexcept( + noexcept(::nlohmann::from_json(std::forward(j), val))) + { + ::nlohmann::from_json(std::forward(j), val); + } + + /*! + @brief convert any value type to a JSON value + + This function is usually called by the constructors of the @ref basic_json + class. + + @param[in,out] j JSON value to write to + @param[in] val value to read from + */ + template + static void to_json(BasicJsonType& j, ValueType&& val) noexcept( + noexcept(::nlohmann::to_json(j, std::forward(val)))) + { + ::nlohmann::to_json(j, std::forward(val)); + } +}; + + +/*! +@brief a class to store JSON values + +@tparam ObjectType type for JSON objects (`std::map` by default; will be used +in @ref object_t) +@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used +in @ref array_t) +@tparam StringType type for JSON strings and object keys (`std::string` by +default; will be used in @ref string_t) +@tparam BooleanType type for JSON booleans (`bool` by default; will be used +in @ref boolean_t) +@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by +default; will be used in @ref number_integer_t) +@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c +`uint64_t` by default; will be used in @ref number_unsigned_t) +@tparam NumberFloatType type for JSON floating-point numbers (`double` by +default; will be used in @ref number_float_t) +@tparam AllocatorType type of the allocator to use (`std::allocator` by +default) +@tparam JSONSerializer the serializer to resolve internal calls to `to_json()` +and `from_json()` (@ref adl_serializer by default) + +@requirement The class satisfies the following concept requirements: +- Basic + - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): + JSON values can be default constructed. The result will be a JSON null + value. + - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): + A JSON value can be constructed from an rvalue argument. + - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): + A JSON value can be copy-constructed from an lvalue expression. + - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): + A JSON value van be assigned from an rvalue argument. + - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): + A JSON value can be copy-assigned from an lvalue expression. + - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): + JSON values can be destructed. +- Layout + - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): + JSON values have + [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): + All non-static data members are private and standard layout types, the + class has no virtual functions or (virtual) base classes. +- Library-wide + - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): + JSON values can be compared with `==`, see @ref + operator==(const_reference,const_reference). + - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): + JSON values can be compared with `<`, see @ref + operator<(const_reference,const_reference). + - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): + Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of + other compatible types, using unqualified function call @ref swap(). + - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): + JSON values can be compared against `std::nullptr_t` objects which are used + to model the `null` value. +- Container + - [Container](http://en.cppreference.com/w/cpp/concept/Container): + JSON values can be used like STL containers and provide iterator access. + - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); + JSON values can be used like STL containers and provide reverse iterator + access. + +@invariant The member variables @a m_value and @a m_type have the following +relationship: +- If `m_type == value_t::object`, then `m_value.object != nullptr`. +- If `m_type == value_t::array`, then `m_value.array != nullptr`. +- If `m_type == value_t::string`, then `m_value.string != nullptr`. +The invariants are checked by member function assert_invariant(). + +@internal +@note ObjectType trick from http://stackoverflow.com/a/9860911 +@endinternal + +@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange +Format](http://rfc7159.net/rfc7159) + +@since version 1.0.0 + +@nosubgrouping +*/ +template < + template class ObjectType = std::map, + template class ArrayType = std::vector, + class StringType = std::string, + class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = adl_serializer + > +class basic_json +{ + private: + template friend struct detail::external_constructor; + /// workaround type for MSVC + using basic_json_t = basic_json; + + public: + using value_t = detail::value_t; + // forward declarations + template class iter_impl; + template class json_reverse_iterator; + class json_pointer; + template + using json_serializer = JSONSerializer; + + ///////////////////// + // container types // + ///////////////////// + + /// @name container types + /// The canonic container types to use @ref basic_json like any other STL + /// container. + /// @{ + + /// the type of elements in a basic_json container + using value_type = basic_json; + + /// the type of an element reference + using reference = value_type&; + /// the type of an element const reference + using const_reference = const value_type&; + + /// a type to represent differences between iterators + using difference_type = std::ptrdiff_t; + /// a type to represent container sizes + using size_type = std::size_t; + + /// the allocator type + using allocator_type = AllocatorType; + + /// the type of an element pointer + using pointer = typename std::allocator_traits::pointer; + /// the type of an element const pointer + using const_pointer = typename std::allocator_traits::const_pointer; + + /// an iterator for a basic_json container + using iterator = iter_impl; + /// a const iterator for a basic_json container + using const_iterator = iter_impl; + /// a reverse iterator for a basic_json container + using reverse_iterator = json_reverse_iterator; + /// a const reverse iterator for a basic_json container + using const_reverse_iterator = json_reverse_iterator; + + /// @} + + + /*! + @brief returns the allocator associated with the container + */ + static allocator_type get_allocator() + { + return allocator_type(); + } + + /*! + @brief returns version information on the library + + This function returns a JSON object with information about the library, + including the version number and information on the platform and compiler. + + @return JSON object holding version information + key | description + ----------- | --------------- + `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version). + `copyright` | The copyright line for the library as string. + `name` | The name of the library as string. + `platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`. + `url` | The URL of the project as string. + `version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string). + + @liveexample{The following code shows an example output of the `meta()` + function.,meta} + + @complexity Constant. + + @since 2.1.0 + */ + static basic_json meta() + { + basic_json result; + + result["copyright"] = "(C) 2013-2017 Niels Lohmann"; + result["name"] = "JSON for Modern C++"; + result["url"] = "https://github.com/nlohmann/json"; + result["version"] = + { + {"string", "2.1.1"}, + {"major", 2}, + {"minor", 1}, + {"patch", 1} + }; + +#ifdef _WIN32 + result["platform"] = "win32"; +#elif defined __linux__ + result["platform"] = "linux"; +#elif defined __APPLE__ + result["platform"] = "apple"; +#elif defined __unix__ + result["platform"] = "unix"; +#else + result["platform"] = "unknown"; +#endif + +#if defined(__clang__) + result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; +#elif defined(__ICC) || defined(__INTEL_COMPILER) + result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; +#elif defined(__GNUC__) || defined(__GNUG__) + result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}}; +#elif defined(__HP_cc) || defined(__HP_aCC) + result["compiler"] = "hp" +#elif defined(__IBMCPP__) + result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; +#elif defined(_MSC_VER) + result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; +#elif defined(__PGI) + result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; +#elif defined(__SUNPRO_CC) + result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; +#else + result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; +#endif + +#ifdef __cplusplus + result["compiler"]["c++"] = std::to_string(__cplusplus); +#else + result["compiler"]["c++"] = "unknown"; +#endif + return result; + } + + + /////////////////////////// + // JSON value data types // + /////////////////////////// + + /// @name JSON value data types + /// The data types to store a JSON value. These types are derived from + /// the template arguments passed to class @ref basic_json. + /// @{ + + /*! + @brief a type for an object + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: + > An object is an unordered collection of zero or more name/value pairs, + > where a name is a string and a value is a string, number, boolean, null, + > object, or array. + + To store objects in C++, a type is defined by the template parameters + described below. + + @tparam ObjectType the container to store objects (e.g., `std::map` or + `std::unordered_map`) + @tparam StringType the type of the keys or names (e.g., `std::string`). + The comparison function `std::less` is used to order elements + inside the container. + @tparam AllocatorType the allocator to use for objects (e.g., + `std::allocator`) + + #### Default type + + With the default values for @a ObjectType (`std::map`), @a StringType + (`std::string`), and @a AllocatorType (`std::allocator`), the default + value for @a object_t is: + + @code {.cpp} + std::map< + std::string, // key_type + basic_json, // value_type + std::less, // key_compare + std::allocator> // allocator_type + > + @endcode + + #### Behavior + + The choice of @a object_t influences the behavior of the JSON class. With + the default type, objects have the following behavior: + + - When all names are unique, objects will be interoperable in the sense + that all software implementations receiving that object will agree on + the name-value mappings. + - When the names within an object are not unique, later stored name/value + pairs overwrite previously stored name/value pairs, leaving the used + names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will + be treated as equal and both stored as `{"key": 1}`. + - Internally, name/value pairs are stored in lexicographical order of the + names. Objects will also be serialized (see @ref dump) in this order. + For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored + and serialized as `{"a": 2, "b": 1}`. + - When comparing objects, the order of the name/value pairs is irrelevant. + This makes objects interoperable in the sense that they will not be + affected by these differences. For instance, `{"b": 1, "a": 2}` and + `{"a": 2, "b": 1}` will be treated as equal. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the object's limit of nesting is not constraint explicitly. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON object. + + #### Storage + + Objects are stored as pointers in a @ref basic_json type. That is, for any + access to object values, a pointer of type `object_t*` must be + dereferenced. + + @sa @ref array_t -- type for an array value + + @since version 1.0.0 + + @note The order name/value pairs are added to the object is *not* + preserved by the library. Therefore, iterating an object may return + name/value pairs in a different order than they were originally stored. In + fact, keys will be traversed in alphabetical order as `std::map` with + `std::less` is used by default. Please note this behavior conforms to [RFC + 7159](http://rfc7159.net/rfc7159), because any order implements the + specified "unordered" nature of JSON objects. + */ + using object_t = ObjectType, + AllocatorType>>; + + /*! + @brief a type for an array + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: + > An array is an ordered sequence of zero or more values. + + To store objects in C++, a type is defined by the template parameters + explained below. + + @tparam ArrayType container type to store arrays (e.g., `std::vector` or + `std::list`) + @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) + + #### Default type + + With the default values for @a ArrayType (`std::vector`) and @a + AllocatorType (`std::allocator`), the default value for @a array_t is: + + @code {.cpp} + std::vector< + basic_json, // value_type + std::allocator // allocator_type + > + @endcode + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the array's limit of nesting is not constraint explicitly. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON array. + + #### Storage + + Arrays are stored as pointers in a @ref basic_json type. That is, for any + access to array values, a pointer of type `array_t*` must be dereferenced. + + @sa @ref object_t -- type for an object value + + @since version 1.0.0 + */ + using array_t = ArrayType>; + + /*! + @brief a type for a string + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: + > A string is a sequence of zero or more Unicode characters. + + To store objects in C++, a type is defined by the template parameter + described below. Unicode values are split by the JSON class into + byte-sized characters during deserialization. + + @tparam StringType the container to store strings (e.g., `std::string`). + Note this container is used for keys/names in objects, see @ref object_t. + + #### Default type + + With the default values for @a StringType (`std::string`), the default + value for @a string_t is: + + @code {.cpp} + std::string + @endcode + + #### Encoding + + Strings are stored in UTF-8 encoding. Therefore, functions like + `std::string::size()` or `std::string::length()` return the number of + bytes in the string rather than the number of characters or glyphs. + + #### String comparison + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > Software implementations are typically required to test names of object + > members for equality. Implementations that transform the textual + > representation into sequences of Unicode code units and then perform the + > comparison numerically, code unit by code unit, are interoperable in the + > sense that implementations will agree in all cases on equality or + > inequality of two strings. For example, implementations that compare + > strings with escaped characters unconverted may incorrectly find that + > `"a\\b"` and `"a\u005Cb"` are not equal. + + This implementation is interoperable as it does compare strings code unit + by code unit. + + #### Storage + + String values are stored as pointers in a @ref basic_json type. That is, + for any access to string values, a pointer of type `string_t*` must be + dereferenced. + + @since version 1.0.0 + */ + using string_t = StringType; + + /*! + @brief a type for a boolean + + [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a + type which differentiates the two literals `true` and `false`. + + To store objects in C++, a type is defined by the template parameter @a + BooleanType which chooses the type to use. + + #### Default type + + With the default values for @a BooleanType (`bool`), the default value for + @a boolean_t is: + + @code {.cpp} + bool + @endcode + + #### Storage + + Boolean values are stored directly inside a @ref basic_json type. + + @since version 1.0.0 + */ + using boolean_t = BooleanType; + + /*! + @brief a type for a number (integer) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store integer numbers in C++, a type is defined by the template + parameter @a NumberIntegerType which chooses the type to use. + + #### Default type + + With the default values for @a NumberIntegerType (`int64_t`), the default + value for @a number_integer_t is: + + @code {.cpp} + int64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `9223372036854775807` (INT64_MAX) and the minimal integer number + that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers + that are out of range will yield over/underflow when used in a + constructor. During deserialization, too large or small integer numbers + will be automatically be stored as @ref number_unsigned_t or @ref + number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange of the exactly supported range [INT64_MIN, + INT64_MAX], this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_integer_t = NumberIntegerType; + + /*! + @brief a type for a number (unsigned) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store unsigned integer numbers in C++, a type is defined by the + template parameter @a NumberUnsignedType which chooses the type to use. + + #### Default type + + With the default values for @a NumberUnsignedType (`uint64_t`), the + default value for @a number_unsigned_t is: + + @code {.cpp} + uint64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `18446744073709551615` (UINT64_MAX) and the minimal integer + number that can be stored is `0`. Integer numbers that are out of range + will yield over/underflow when used in a constructor. During + deserialization, too large or small integer numbers will be automatically + be stored as @ref number_integer_t or @ref number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange (when considered in conjunction with the + number_integer_t type) of the exactly supported range [0, UINT64_MAX], + this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + @sa @ref number_integer_t -- type for number values (integer) + + @since version 2.0.0 + */ + using number_unsigned_t = NumberUnsignedType; + + /*! + @brief a type for a number (floating-point) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store floating-point numbers in C++, a type is defined by the template + parameter @a NumberFloatType which chooses the type to use. + + #### Default type + + With the default values for @a NumberFloatType (`double`), the default + value for @a number_float_t is: + + @code {.cpp} + double + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in floating-point literals will be ignored. Internally, + the value will be stored as decimal number. For instance, the C++ + floating-point literal `01.2` will be serialized to `1.2`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > This specification allows implementations to set limits on the range and + > precision of numbers accepted. Since software that implements IEEE + > 754-2008 binary64 (double precision) numbers is generally available and + > widely used, good interoperability can be achieved by implementations + > that expect no more precision or range than these provide, in the sense + > that implementations will approximate JSON numbers within the expected + > precision. + + This implementation does exactly follow this approach, as it uses double + precision floating-point numbers. Note values smaller than + `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` + will be stored as NaN internally and be serialized to `null`. + + #### Storage + + Floating-point number values are stored directly inside a @ref basic_json + type. + + @sa @ref number_integer_t -- type for number values (integer) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_float_t = NumberFloatType; + + /// @} + + private: + + /// helper for exception-safe object creation + template + static T* create(Args&& ... args) + { + AllocatorType alloc; + auto deleter = [&](T * object) + { + alloc.deallocate(object, 1); + }; + std::unique_ptr object(alloc.allocate(1), deleter); + alloc.construct(object.get(), std::forward(args)...); + assert(object != nullptr); + return object.release(); + } + + //////////////////////// + // JSON value storage // + //////////////////////// + + /*! + @brief a JSON value + + The actual storage for a JSON value of the @ref basic_json class. This + union combines the different storage types for the JSON value types + defined in @ref value_t. + + JSON type | value_t type | used type + --------- | --------------- | ------------------------ + object | object | pointer to @ref object_t + array | array | pointer to @ref array_t + string | string | pointer to @ref string_t + boolean | boolean | @ref boolean_t + number | number_integer | @ref number_integer_t + number | number_unsigned | @ref number_unsigned_t + number | number_float | @ref number_float_t + null | null | *no value is stored* + + @note Variable-length types (objects, arrays, and strings) are stored as + pointers. The size of the union should not exceed 64 bits if the default + value types are used. + + @since version 1.0.0 + */ + union json_value + { + /// object (stored with pointer to save storage) + object_t* object; + /// array (stored with pointer to save storage) + array_t* array; + /// string (stored with pointer to save storage) + string_t* string; + /// boolean + boolean_t boolean; + /// number (integer) + number_integer_t number_integer; + /// number (unsigned integer) + number_unsigned_t number_unsigned; + /// number (floating-point) + number_float_t number_float; + + /// default constructor (for null values) + json_value() = default; + /// constructor for booleans + json_value(boolean_t v) noexcept : boolean(v) {} + /// constructor for numbers (integer) + json_value(number_integer_t v) noexcept : number_integer(v) {} + /// constructor for numbers (unsigned) + json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} + /// constructor for numbers (floating-point) + json_value(number_float_t v) noexcept : number_float(v) {} + /// constructor for empty values of a given type + json_value(value_t t) + { + switch (t) + { + case value_t::object: + { + object = create(); + break; + } + + case value_t::array: + { + array = create(); + break; + } + + case value_t::string: + { + string = create(""); + break; + } + + case value_t::boolean: + { + boolean = boolean_t(false); + break; + } + + case value_t::number_integer: + { + number_integer = number_integer_t(0); + break; + } + + case value_t::number_unsigned: + { + number_unsigned = number_unsigned_t(0); + break; + } + + case value_t::number_float: + { + number_float = number_float_t(0.0); + break; + } + + case value_t::null: + { + break; + } + + default: + { + if (t == value_t::null) + { + JSON_THROW(std::domain_error("961c151d2e87f2686a955a9be24d316f1362bf21 2.1.1")); // LCOV_EXCL_LINE + } + break; + } + } + } + + /// constructor for strings + json_value(const string_t& value) + { + string = create(value); + } + + /// constructor for objects + json_value(const object_t& value) + { + object = create(value); + } + + /// constructor for arrays + json_value(const array_t& value) + { + array = create(value); + } + }; + + /*! + @brief checks the class invariants + + This function asserts the class invariants. It needs to be called at the + end of every constructor to make sure that created objects respect the + invariant. Furthermore, it has to be called each time the type of a JSON + value is changed, because the invariant expresses a relationship between + @a m_type and @a m_value. + */ + void assert_invariant() const + { + assert(m_type != value_t::object or m_value.object != nullptr); + assert(m_type != value_t::array or m_value.array != nullptr); + assert(m_type != value_t::string or m_value.string != nullptr); + } + + public: + ////////////////////////// + // JSON parser callback // + ////////////////////////// + + /*! + @brief JSON callback events + + This enumeration lists the parser events that can trigger calling a + callback function of type @ref parser_callback_t during parsing. + + @image html callback_events.png "Example when certain parse events are triggered" + + @since version 1.0.0 + */ + enum class parse_event_t : uint8_t + { + /// the parser read `{` and started to process a JSON object + object_start, + /// the parser read `}` and finished processing a JSON object + object_end, + /// the parser read `[` and started to process a JSON array + array_start, + /// the parser read `]` and finished processing a JSON array + array_end, + /// the parser read a key of a value in an object + key, + /// the parser finished reading a JSON value + value + }; + + /*! + @brief per-element parser callback type + + With a parser callback function, the result of parsing a JSON text can be + influenced. When passed to @ref parse(std::istream&, const + parser_callback_t) or @ref parse(const CharT, const parser_callback_t), + it is called on certain events (passed as @ref parse_event_t via parameter + @a event) with a set recursion depth @a depth and context JSON value + @a parsed. The return value of the callback function is a boolean + indicating whether the element that emitted the callback shall be kept or + not. + + We distinguish six scenarios (determined by the event type) in which the + callback function can be called. The following table describes the values + of the parameters @a depth, @a event, and @a parsed. + + parameter @a event | description | parameter @a depth | parameter @a parsed + ------------------ | ----------- | ------------------ | ------------------- + parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded + parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key + parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object + parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded + parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array + parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + Discarding a value (i.e., returning `false`) has different effects + depending on the context in which function was called: + + - Discarded values in structured types are skipped. That is, the parser + will behave as if the discarded value was never read. + - In case a value outside a structured type is skipped, it is replaced + with `null`. This case happens if the top-level element is skipped. + + @param[in] depth the depth of the recursion during parsing + + @param[in] event an event of type parse_event_t indicating the context in + the callback function has been called + + @param[in,out] parsed the current intermediate parse result; note that + writing to this value has no effect for parse_event_t::key events + + @return Whether the JSON value which called the function during parsing + should be kept (`true`) or not (`false`). In the latter case, it is either + skipped completely or replaced by an empty discarded object. + + @sa @ref parse(std::istream&, parser_callback_t) or + @ref parse(const CharT, const parser_callback_t) for examples + + @since version 1.0.0 + */ + using parser_callback_t = std::function; + + + ////////////////// + // constructors // + ////////////////// + + /// @name constructors and destructors + /// Constructors of class @ref basic_json, copy/move constructor, copy + /// assignment, static functions creating objects, and the destructor. + /// @{ + + /*! + @brief create an empty value with a given type + + Create an empty JSON value with a given type. The value will be default + initialized with an empty value which depends on the type: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @param[in] value_type the type of the value to create + + @complexity Constant. + + @throw std::bad_alloc if allocation for object, array, or string value + fails + + @liveexample{The following code shows the constructor for different @ref + value_t values,basic_json__value_t} + + @since version 1.0.0 + */ + basic_json(const value_t value_type) + : m_type(value_type), m_value(value_type) + { + assert_invariant(); + } + + /*! + @brief create a null object + + Create a `null` JSON value. It either takes a null pointer as parameter + (explicitly creating `null`) or no parameter (implicitly creating `null`). + The passed null pointer itself is not read -- it is only used to choose + the right constructor. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @liveexample{The following code shows the constructor with and without a + null pointer parameter.,basic_json__nullptr_t} + + @since version 1.0.0 + */ + basic_json(std::nullptr_t = nullptr) noexcept + : basic_json(value_t::null) + { + assert_invariant(); + } + + /*! + @brief create a JSON value + + This is a "catch all" constructor for all compatible JSON types; that is, + types for which a `to_json()` method exsits. The constructor forwards the + parameter @a val to that method (to `json_serializer::to_json` method + with `U = uncvref_t`, to be exact). + + Template type @a CompatibleType includes, but is not limited to, the + following types: + - **arrays**: @ref array_t and all kinds of compatible containers such as + `std::vector`, `std::deque`, `std::list`, `std::forward_list`, + `std::array`, `std::set`, `std::unordered_set`, `std::multiset`, and + `unordered_multiset` with a `value_type` from which a @ref basic_json + value can be constructed. + - **objects**: @ref object_t and all kinds of compatible associative + containers such as `std::map`, `std::unordered_map`, `std::multimap`, + and `std::unordered_multimap` with a `key_type` compatible to + @ref string_t and a `value_type` from which a @ref basic_json value can + be constructed. + - **strings**: @ref string_t, string literals, and all compatible string + containers can be used. + - **numbers**: @ref number_integer_t, @ref number_unsigned_t, + @ref number_float_t, and all convertible number types such as `int`, + `size_t`, `int64_t`, `float` or `double` can be used. + - **boolean**: @ref boolean_t / `bool` can be used. + + See the examples below. + + @tparam CompatibleType a type such that: + - @a CompatibleType is not derived from `std::istream`, + - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move + constructors), + - @a CompatibleType is not a @ref basic_json nested type (e.g., + @ref json_pointer, @ref iterator, etc ...) + - @ref @ref json_serializer has a + `to_json(basic_json_t&, CompatibleType&&)` method + + @tparam U = `uncvref_t` + + @param[in] val the value to be forwarded + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @throw what `json_serializer::to_json()` throws + + @liveexample{The following code shows the constructor with several + compatible types.,basic_json__CompatibleType} + + @since version 2.1.0 + */ + template, + detail::enable_if_t::value and + not std::is_same::value and + not detail::is_basic_json_nested_type< + basic_json_t, U>::value and + detail::has_to_json::value, + int> = 0> + basic_json(CompatibleType && val) noexcept(noexcept(JSONSerializer::to_json( + std::declval(), std::forward(val)))) + { + JSONSerializer::to_json(*this, std::forward(val)); + assert_invariant(); + } + + /*! + @brief create a container (array or object) from an initializer list + + Creates a JSON value of type array or object from the passed initializer + list @a init. In case @a type_deduction is `true` (default), the type of + the JSON value to be created is deducted from the initializer list @a init + according to the following rules: + + 1. If the list is empty, an empty JSON object value `{}` is created. + 2. If the list consists of pairs whose first element is a string, a JSON + object value is created where the first elements of the pairs are + treated as keys and the second elements are as values. + 3. In all other cases, an array is created. + + The rules aim to create the best fit between a C++ initializer list and + JSON values. The rationale is as follows: + + 1. The empty initializer list is written as `{}` which is exactly an empty + JSON object. + 2. C++ has now way of describing mapped types other than to list a list of + pairs. As JSON requires that keys must be of type string, rule 2 is the + weakest constraint one can pose on initializer lists to interpret them + as an object. + 3. In all other cases, the initializer list could not be interpreted as + JSON object type, so interpreting it as JSON array type is safe. + + With the rules described above, the following JSON values cannot be + expressed by an initializer list: + + - the empty array (`[]`): use @ref array(std::initializer_list) + with an empty initializer list in this case + - arrays whose elements satisfy rule 2: use @ref + array(std::initializer_list) with the same initializer list + in this case + + @note When used without parentheses around an empty initializer list, @ref + basic_json() is called instead of this function, yielding the JSON null + value. + + @param[in] init initializer list with JSON values + + @param[in] type_deduction internal parameter; when set to `true`, the type + of the JSON value is deducted from the initializer list @a init; when set + to `false`, the type provided via @a manual_type is forced. This mode is + used by the functions @ref array(std::initializer_list) and + @ref object(std::initializer_list). + + @param[in] manual_type internal parameter; when @a type_deduction is set + to `false`, the created JSON value will use the provided type (only @ref + value_t::array and @ref value_t::object are valid); when @a type_deduction + is set to `true`, this parameter has no effect + + @throw std::domain_error if @a type_deduction is `false`, @a manual_type + is `value_t::object`, but @a init contains an element which is not a pair + whose first element is a string; example: `"cannot create object from + initializer list"` + + @complexity Linear in the size of the initializer list @a init. + + @liveexample{The example below shows how JSON values are created from + initializer lists.,basic_json__list_init_t} + + @sa @ref array(std::initializer_list) -- create a JSON array + value from an initializer list + @sa @ref object(std::initializer_list) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + basic_json(std::initializer_list init, + bool type_deduction = true, + value_t manual_type = value_t::array) + { + // check if each element is an array with two elements whose first + // element is a string + bool is_an_object = std::all_of(init.begin(), init.end(), + [](const basic_json & element) + { + return element.is_array() and element.size() == 2 and element[0].is_string(); + }); + + // adjust type if type deduction is not wanted + if (not type_deduction) + { + // if array is wanted, do not create an object though possible + if (manual_type == value_t::array) + { + is_an_object = false; + } + + // if object is wanted but impossible, throw an exception + if (manual_type == value_t::object and not is_an_object) + { + JSON_THROW(std::domain_error("cannot create object from initializer list")); + } + } + + if (is_an_object) + { + // the initializer list is a list of pairs -> create object + m_type = value_t::object; + m_value = value_t::object; + + std::for_each(init.begin(), init.end(), [this](const basic_json & element) + { + m_value.object->emplace(*(element[0].m_value.string), element[1]); + }); + } + else + { + // the initializer list describes an array -> create array + m_type = value_t::array; + m_value.array = create(init); + } + + assert_invariant(); + } + + /*! + @brief explicitly create an array from an initializer list + + Creates a JSON array value from a given initializer list. That is, given a + list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the + initializer list is empty, the empty array `[]` is created. + + @note This function is only needed to express two edge cases that cannot + be realized with the initializer list constructor (@ref + basic_json(std::initializer_list, bool, value_t)). These cases + are: + 1. creating an array whose elements are all pairs whose first element is a + string -- in this case, the initializer list constructor would create an + object, taking the first elements as keys + 2. creating an empty array -- passing the empty initializer list to the + initializer list constructor yields an empty object + + @param[in] init initializer list with JSON values to create an array from + (optional) + + @return JSON array value + + @complexity Linear in the size of @a init. + + @liveexample{The following code shows an example for the `array` + function.,array} + + @sa @ref basic_json(std::initializer_list, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref object(std::initializer_list) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + static basic_json array(std::initializer_list init = + std::initializer_list()) + { + return basic_json(init, false, value_t::array); + } + + /*! + @brief explicitly create an object from an initializer list + + Creates a JSON object value from a given initializer list. The initializer + lists elements must be pairs, and their first elements must be strings. If + the initializer list is empty, the empty object `{}` is created. + + @note This function is only added for symmetry reasons. In contrast to the + related function @ref array(std::initializer_list), there are + no cases which can only be expressed by this function. That is, any + initializer list @a init can also be passed to the initializer list + constructor @ref basic_json(std::initializer_list, bool, + value_t). + + @param[in] init initializer list to create an object from (optional) + + @return JSON object value + + @throw std::domain_error if @a init is not a pair whose first elements are + strings; thrown by + @ref basic_json(std::initializer_list, bool, value_t) + + @complexity Linear in the size of @a init. + + @liveexample{The following code shows an example for the `object` + function.,object} + + @sa @ref basic_json(std::initializer_list, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref array(std::initializer_list) -- create a JSON array + value from an initializer list + + @since version 1.0.0 + */ + static basic_json object(std::initializer_list init = + std::initializer_list()) + { + return basic_json(init, false, value_t::object); + } + + /*! + @brief construct an array with count copies of given value + + Constructs a JSON array value by creating @a cnt copies of a passed value. + In case @a cnt is `0`, an empty array is created. As postcondition, + `std::distance(begin(),end()) == cnt` holds. + + @param[in] cnt the number of JSON copies of @a val to create + @param[in] val the JSON value to copy + + @complexity Linear in @a cnt. + + @liveexample{The following code shows examples for the @ref + basic_json(size_type\, const basic_json&) + constructor.,basic_json__size_type_basic_json} + + @since version 1.0.0 + */ + basic_json(size_type cnt, const basic_json& val) + : m_type(value_t::array) + { + m_value.array = create(cnt, val); + assert_invariant(); + } + + /*! + @brief construct a JSON container given an iterator range + + Constructs the JSON value with the contents of the range `[first, last)`. + The semantics depends on the different types a JSON value can have: + - In case of primitive types (number, boolean, or string), @a first must + be `begin()` and @a last must be `end()`. In this case, the value is + copied. Otherwise, std::out_of_range is thrown. + - In case of structured types (array, object), the constructor behaves as + similar versions for `std::vector`. + - In case of a null type, std::domain_error is thrown. + + @tparam InputIT an input iterator type (@ref iterator or @ref + const_iterator) + + @param[in] first begin of the range to copy from (included) + @param[in] last end of the range to copy from (excluded) + + @pre Iterators @a first and @a last must be initialized. **This + precondition is enforced with an assertion.** + + @throw std::domain_error if iterators are not compatible; that is, do not + belong to the same JSON value; example: `"iterators are not compatible"` + @throw std::out_of_range if iterators are for a primitive type (number, + boolean, or string) where an out of range error can be detected easily; + example: `"iterators out of range"` + @throw std::bad_alloc if allocation for object, array, or string fails + @throw std::domain_error if called with a null value; example: `"cannot + use construct with iterators from null"` + + @complexity Linear in distance between @a first and @a last. + + @liveexample{The example below shows several ways to create JSON values by + specifying a subrange with iterators.,basic_json__InputIt_InputIt} + + @since version 1.0.0 + */ + template::value or + std::is_same::value, int>::type = 0> + basic_json(InputIT first, InputIT last) + { + assert(first.m_object != nullptr); + assert(last.m_object != nullptr); + + // make sure iterator fits the current value + if (first.m_object != last.m_object) + { + JSON_THROW(std::domain_error("iterators are not compatible")); + } + + // copy type from first iterator + m_type = first.m_object->m_type; + + // check if iterator range is complete for primitive values + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) + { + JSON_THROW(std::out_of_range("iterators out of range")); + } + break; + } + + default: + { + break; + } + } + + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = first.m_object->m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = first.m_object->m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value.number_float = first.m_object->m_value.number_float; + break; + } + + case value_t::boolean: + { + m_value.boolean = first.m_object->m_value.boolean; + break; + } + + case value_t::string: + { + m_value = *first.m_object->m_value.string; + break; + } + + case value_t::object: + { + m_value.object = create(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + m_value.array = create(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + default: + { + JSON_THROW(std::domain_error("cannot use construct with iterators from " + first.m_object->type_name())); + } + } + + assert_invariant(); + } + + /*! + @brief construct a JSON value given an input stream + + @param[in,out] i stream to read a serialized JSON value from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @deprecated This constructor is deprecated and will be removed in version + 3.0.0 to unify the interface of the library. Deserialization will be + done by stream operators or by calling one of the `parse` functions, + e.g. @ref parse(std::istream&, const parser_callback_t). That is, calls + like `json j(i);` for an input stream @a i need to be replaced by + `json j = json::parse(i);`. See the example below. + + @liveexample{The example below demonstrates constructing a JSON value from + a `std::stringstream` with and without callback + function.,basic_json__istream} + + @since version 2.0.0, deprecated in version 2.0.3, to be removed in + version 3.0.0 + */ + JSON_DEPRECATED + explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr) + { + *this = parser(i, cb).parse(); + assert_invariant(); + } + + /////////////////////////////////////// + // other constructors and destructor // + /////////////////////////////////////// + + /*! + @brief copy constructor + + Creates a copy of a given JSON value. + + @param[in] other the JSON value to copy + + @complexity Linear in the size of @a other. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - As postcondition, it holds: `other == basic_json(other)`. + + @throw std::bad_alloc if allocation for object, array, or string fails. + + @liveexample{The following code shows an example for the copy + constructor.,basic_json__basic_json} + + @since version 1.0.0 + */ + basic_json(const basic_json& other) + : m_type(other.m_type) + { + // check of passed value is valid + other.assert_invariant(); + + switch (m_type) + { + case value_t::object: + { + m_value = *other.m_value.object; + break; + } + + case value_t::array: + { + m_value = *other.m_value.array; + break; + } + + case value_t::string: + { + m_value = *other.m_value.string; + break; + } + + case value_t::boolean: + { + m_value = other.m_value.boolean; + break; + } + + case value_t::number_integer: + { + m_value = other.m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value = other.m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value = other.m_value.number_float; + break; + } + + default: + { + break; + } + } + + assert_invariant(); + } + + /*! + @brief move constructor + + Move constructor. Constructs a JSON value with the contents of the given + value @a other using move semantics. It "steals" the resources from @a + other and leaves it as JSON null value. + + @param[in,out] other value to move to this object + + @post @a other is a JSON null value + + @complexity Constant. + + @liveexample{The code below shows the move constructor explicitly called + via std::move.,basic_json__moveconstructor} + + @since version 1.0.0 + */ + basic_json(basic_json&& other) noexcept + : m_type(std::move(other.m_type)), + m_value(std::move(other.m_value)) + { + // check that passed value is valid + other.assert_invariant(); + + // invalidate payload + other.m_type = value_t::null; + other.m_value = {}; + + assert_invariant(); + } + + /*! + @brief copy assignment + + Copy assignment operator. Copies a JSON value via the "copy and swap" + strategy: It is expressed in terms of the copy constructor, destructor, + and the swap() member function. + + @param[in] other value to copy from + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + + @liveexample{The code below shows and example for the copy assignment. It + creates a copy of value `a` which is then swapped with `b`. Finally\, the + copy of `a` (which is the null value after the swap) is + destroyed.,basic_json__copyassignment} + + @since version 1.0.0 + */ + reference& operator=(basic_json other) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + // check that passed value is valid + other.assert_invariant(); + + using std::swap; + swap(m_type, other.m_type); + swap(m_value, other.m_value); + + assert_invariant(); + return *this; + } + + /*! + @brief destructor + + Destroys the JSON value and frees all allocated memory. + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - All stored elements are destroyed and all memory is freed. + + @since version 1.0.0 + */ + ~basic_json() + { + assert_invariant(); + + switch (m_type) + { + case value_t::object: + { + AllocatorType alloc; + alloc.destroy(m_value.object); + alloc.deallocate(m_value.object, 1); + break; + } + + case value_t::array: + { + AllocatorType alloc; + alloc.destroy(m_value.array); + alloc.deallocate(m_value.array, 1); + break; + } + + case value_t::string: + { + AllocatorType alloc; + alloc.destroy(m_value.string); + alloc.deallocate(m_value.string, 1); + break; + } + + default: + { + // all other types need no specific destructor + break; + } + } + } + + /// @} + + public: + /////////////////////// + // object inspection // + /////////////////////// + + /// @name object inspection + /// Functions to inspect the type of a JSON value. + /// @{ + + /*! + @brief serialization + + Serialization function for JSON values. The function tries to mimic + Python's `json.dumps()` function, and currently supports its @a indent + parameter. + + @param[in] indent If indent is nonnegative, then array elements and object + members will be pretty-printed with that indent level. An indent level of + `0` will only insert newlines. `-1` (the default) selects the most compact + representation. + + @return string containing the serialization of the JSON value + + @complexity Linear. + + @liveexample{The following example shows the effect of different @a indent + parameters to the result of the serialization.,dump} + + @see https://docs.python.org/2/library/json.html#json.dump + + @since version 1.0.0 + */ + string_t dump(const int indent = -1) const + { + std::stringstream ss; + + if (indent >= 0) + { + dump(ss, true, static_cast(indent)); + } + else + { + dump(ss, false, 0); + } + + return ss.str(); + } + + /*! + @brief return the type of the JSON value (explicit) + + Return the type of the JSON value as a value from the @ref value_t + enumeration. + + @return the type of the JSON value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `type()` for all JSON + types.,type} + + @since version 1.0.0 + */ + constexpr value_t type() const noexcept + { + return m_type; + } + + /*! + @brief return whether type is primitive + + This function returns true iff the JSON type is primitive (string, number, + boolean, or null). + + @return `true` if type is primitive (string, number, boolean, or null), + `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_primitive()` for all JSON + types.,is_primitive} + + @sa @ref is_structured() -- returns whether JSON value is structured + @sa @ref is_null() -- returns whether JSON value is `null` + @sa @ref is_string() -- returns whether JSON value is a string + @sa @ref is_boolean() -- returns whether JSON value is a boolean + @sa @ref is_number() -- returns whether JSON value is a number + + @since version 1.0.0 + */ + constexpr bool is_primitive() const noexcept + { + return is_null() or is_string() or is_boolean() or is_number(); + } + + /*! + @brief return whether type is structured + + This function returns true iff the JSON type is structured (array or + object). + + @return `true` if type is structured (array or object), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_structured()` for all JSON + types.,is_structured} + + @sa @ref is_primitive() -- returns whether value is primitive + @sa @ref is_array() -- returns whether value is an array + @sa @ref is_object() -- returns whether value is an object + + @since version 1.0.0 + */ + constexpr bool is_structured() const noexcept + { + return is_array() or is_object(); + } + + /*! + @brief return whether value is null + + This function returns true iff the JSON value is null. + + @return `true` if type is null, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_null()` for all JSON + types.,is_null} + + @since version 1.0.0 + */ + constexpr bool is_null() const noexcept + { + return m_type == value_t::null; + } + + /*! + @brief return whether value is a boolean + + This function returns true iff the JSON value is a boolean. + + @return `true` if type is boolean, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_boolean()` for all JSON + types.,is_boolean} + + @since version 1.0.0 + */ + constexpr bool is_boolean() const noexcept + { + return m_type == value_t::boolean; + } + + /*! + @brief return whether value is a number + + This function returns true iff the JSON value is a number. This includes + both integer and floating-point values. + + @return `true` if type is number (regardless whether integer, unsigned + integer or floating-type), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number()` for all JSON + types.,is_number} + + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number() const noexcept + { + return is_number_integer() or is_number_float(); + } + + /*! + @brief return whether value is an integer number + + This function returns true iff the JSON value is an integer or unsigned + integer number. This excludes floating-point values. + + @return `true` if type is an integer or unsigned integer number, `false` + otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_integer()` for all + JSON types.,is_number_integer} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number_integer() const noexcept + { + return m_type == value_t::number_integer or m_type == value_t::number_unsigned; + } + + /*! + @brief return whether value is an unsigned integer number + + This function returns true iff the JSON value is an unsigned integer + number. This excludes floating-point and (signed) integer values. + + @return `true` if type is an unsigned integer number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_unsigned()` for all + JSON types.,is_number_unsigned} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 2.0.0 + */ + constexpr bool is_number_unsigned() const noexcept + { + return m_type == value_t::number_unsigned; + } + + /*! + @brief return whether value is a floating-point number + + This function returns true iff the JSON value is a floating-point number. + This excludes integer and unsigned integer values. + + @return `true` if type is a floating-point number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_float()` for all + JSON types.,is_number_float} + + @sa @ref is_number() -- check if value is number + @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + + @since version 1.0.0 + */ + constexpr bool is_number_float() const noexcept + { + return m_type == value_t::number_float; + } + + /*! + @brief return whether value is an object + + This function returns true iff the JSON value is an object. + + @return `true` if type is object, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_object()` for all JSON + types.,is_object} + + @since version 1.0.0 + */ + constexpr bool is_object() const noexcept + { + return m_type == value_t::object; + } + + /*! + @brief return whether value is an array + + This function returns true iff the JSON value is an array. + + @return `true` if type is array, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_array()` for all JSON + types.,is_array} + + @since version 1.0.0 + */ + constexpr bool is_array() const noexcept + { + return m_type == value_t::array; + } + + /*! + @brief return whether value is a string + + This function returns true iff the JSON value is a string. + + @return `true` if type is string, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_string()` for all JSON + types.,is_string} + + @since version 1.0.0 + */ + constexpr bool is_string() const noexcept + { + return m_type == value_t::string; + } + + /*! + @brief return whether value is discarded + + This function returns true iff the JSON value was discarded during parsing + with a callback function (see @ref parser_callback_t). + + @note This function will always be `false` for JSON values after parsing. + That is, discarded values can only occur during parsing, but will be + removed when inside a structured value or replaced by null in other cases. + + @return `true` if type is discarded, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_discarded()` for all JSON + types.,is_discarded} + + @since version 1.0.0 + */ + constexpr bool is_discarded() const noexcept + { + return m_type == value_t::discarded; + } + + /*! + @brief return the type of the JSON value (implicit) + + Implicitly return the type of the JSON value as a value from the @ref + value_t enumeration. + + @return the type of the JSON value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies the @ref value_t operator for + all JSON types.,operator__value_t} + + @since version 1.0.0 + */ + constexpr operator value_t() const noexcept + { + return m_type; + } + + /// @} + + private: + ////////////////// + // value access // + ////////////////// + + /// get a boolean (explicit) + boolean_t get_impl(boolean_t* /*unused*/) const + { + if (is_boolean()) + { + return m_value.boolean; + } + + JSON_THROW(std::domain_error("type must be boolean, but is " + type_name())); + } + + /// get a pointer to the value (object) + object_t* get_impl_ptr(object_t* /*unused*/) noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (object) + constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (array) + array_t* get_impl_ptr(array_t* /*unused*/) noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (array) + constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (string) + string_t* get_impl_ptr(string_t* /*unused*/) noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (string) + constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (boolean) + boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (boolean) + constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (integer number) + number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (integer number) + constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (unsigned number) + number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (unsigned number) + constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (floating-point number) + number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /// get a pointer to the value (floating-point number) + constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /*! + @brief helper function to implement get_ref() + + This funcion helps to implement get_ref() without code duplication for + const and non-const overloads + + @tparam ThisType will be deduced as `basic_json` or `const basic_json` + + @throw std::domain_error if ReferenceType does not match underlying value + type of the current JSON + */ + template + static ReferenceType get_ref_impl(ThisType& obj) + { + // helper type + using PointerType = typename std::add_pointer::type; + + // delegate the call to get_ptr<>() + auto ptr = obj.template get_ptr(); + + if (ptr != nullptr) + { + return *ptr; + } + + JSON_THROW(std::domain_error("incompatible ReferenceType for get_ref, actual type is " + + obj.type_name())); + } + + public: + /// @name value access + /// Direct access to the stored value of a JSON value. + /// @{ + + /*! + @brief get special-case overload + + This overloads avoids a lot of template boilerplate, it can be seen as the + identity method + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this + + @complexity Constant. + + @since version 2.1.0 + */ + template < + typename BasicJsonType, + detail::enable_if_t::type, + basic_json_t>::value, + int> = 0 > + basic_json get() const + { + return *this; + } + + /*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value + which is [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) + and [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer has a `from_json()` method of the form + `void from_json(const @ref basic_json&, ValueType&)`, and + - @ref json_serializer does not have a `from_json()` method of + the form `ValueType from_json(const @ref basic_json&)` + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get__ValueType_const} + + @since version 2.1.0 + */ + template < + typename ValueTypeCV, + typename ValueType = detail::uncvref_t, + detail::enable_if_t < + not std::is_same::value and + detail::has_from_json::value and + not detail::has_non_default_from_json::value, + int > = 0 > + ValueType get() const noexcept(noexcept( + JSONSerializer::from_json(std::declval(), std::declval()))) + { + // we cannot static_assert on ValueTypeCV being non-const, because + // there is support for get(), which is why we + // still need the uncvref + static_assert(not std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + static_assert(std::is_default_constructible::value, + "types must be DefaultConstructible when used with get()"); + + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + } + + /*! + @brief get a value (explicit); special case + + Explicit type conversion between the JSON value and a compatible value + which is **not** [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) + and **not** [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + return JSONSerializer::from_json(*this); + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json and + - @ref json_serializer has a `from_json()` method of the form + `ValueType from_json(const @ref basic_json&)` + + @note If @ref json_serializer has both overloads of + `from_json()`, this one is chosen. + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @since version 2.1.0 + */ + template < + typename ValueTypeCV, + typename ValueType = detail::uncvref_t, + detail::enable_if_t::value and + detail::has_non_default_from_json::value, int> = 0 > + ValueType get() const noexcept(noexcept( + JSONSerializer::from_json(std::declval()))) + { + static_assert(not std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + return JSONSerializer::from_json(*this); + } + + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object + changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template::value, int>::type = 0> + PointerType get() noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template::value, int>::type = 0> + constexpr const PointerType get() const noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (implicit) + + Implicit pointer access to the internally stored JSON value. No copies are + made. + + @warning Writing data to the pointee of the result yields an undefined + state. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. Enforced by a static + assertion. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get_ptr} + + @since version 1.0.0 + */ + template::value, int>::type = 0> + PointerType get_ptr() noexcept + { + // get the type of the PointerType (remove pointer and const) + using pointee_t = typename std::remove_const::type>::type>::type; + // make sure the type matches the allowed types + static_assert( + std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + , "incompatible pointer type"); + + // delegate the call to get_impl_ptr<>() + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a pointer value (implicit) + @copydoc get_ptr() + */ + template::value and + std::is_const::type>::value, int>::type = 0> + constexpr const PointerType get_ptr() const noexcept + { + // get the type of the PointerType (remove pointer and const) + using pointee_t = typename std::remove_const::type>::type>::type; + // make sure the type matches the allowed types + static_assert( + std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + , "incompatible pointer type"); + + // delegate the call to get_impl_ptr<>() const + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a reference value (implicit) + + Implicit reference access to the internally stored JSON value. No copies + are made. + + @warning Writing data to the referee of the result yields an undefined + state. + + @tparam ReferenceType reference type; must be a reference to @ref array_t, + @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or + @ref number_float_t. Enforced by static assertion. + + @return reference to the internally stored JSON value if the requested + reference type @a ReferenceType fits to the JSON value; throws + std::domain_error otherwise + + @throw std::domain_error in case passed type @a ReferenceType is + incompatible with the stored JSON value + + @complexity Constant. + + @liveexample{The example shows several calls to `get_ref()`.,get_ref} + + @since version 1.1.0 + */ + template::value, int>::type = 0> + ReferenceType get_ref() + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a reference value (implicit) + @copydoc get_ref() + */ + template::value and + std::is_const::type>::value, int>::type = 0> + ReferenceType get_ref() const + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a value (implicit) + + Implicit type conversion between the JSON value and a compatible value. + The call is realized by calling @ref get() const. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays. The character type of @ref string_t + as well as an initializer list of this type is excluded to avoid + ambiguities as these types implicitly convert to `std::string`. + + @return copy of the JSON value, converted to type @a ValueType + + @throw std::domain_error in case passed type @a ValueType is incompatible + to JSON, thrown by @ref get() const + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,operator__ValueType} + + @since version 1.0.0 + */ + template < typename ValueType, typename std::enable_if < + not std::is_pointer::value and + not std::is_same::value +#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 + and not std::is_same>::value +#endif + , int >::type = 0 > + operator ValueType() const + { + // delegate the call to get<>() const + return get(); + } + + /// @} + + + //////////////////// + // element access // + //////////////////// + + /// @name element access + /// Access to the JSON value. + /// @{ + + /*! + @brief access specified array element with bounds checking + + Returns a reference to the element at specified location @a idx, with + bounds checking. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw std::domain_error if the JSON value is not an array; example: + `"cannot use at() with string"` + @throw std::out_of_range if the index @a idx is out of range of the array; + that is, `idx >= size()`; example: `"array index 7 is out of range"` + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read and + written using `at()`.,at__size_type} + + @since version 1.0.0 + */ + reference at(size_type idx) + { + // at only works for arrays + if (is_array()) + { + JSON_TRY + { + return m_value.array->at(idx); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); + } + } + else + { + JSON_THROW(std::domain_error("cannot use at() with " + type_name())); + } + } + + /*! + @brief access specified array element with bounds checking + + Returns a const reference to the element at specified location @a idx, + with bounds checking. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw std::domain_error if the JSON value is not an array; example: + `"cannot use at() with string"` + @throw std::out_of_range if the index @a idx is out of range of the array; + that is, `idx >= size()`; example: `"array index 7 is out of range"` + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + `at()`.,at__size_type_const} + + @since version 1.0.0 + */ + const_reference at(size_type idx) const + { + // at only works for arrays + if (is_array()) + { + JSON_TRY + { + return m_value.array->at(idx); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); + } + } + else + { + JSON_THROW(std::domain_error("cannot use at() with " + type_name())); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a reference to the element at with specified key @a key, with + bounds checking. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if the JSON value is not an object; example: + `"cannot use at() with boolean"` + @throw std::out_of_range if the key @a key is is not stored in the object; + that is, `find(key) == end()`; example: `"key "the fast" not found"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using `at()`.,at__object_t_key_type} + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + reference at(const typename object_t::key_type& key) + { + // at only works for objects + if (is_object()) + { + JSON_TRY + { + return m_value.object->at(key); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(std::out_of_range("key '" + key + "' not found")); + } + } + else + { + JSON_THROW(std::domain_error("cannot use at() with " + type_name())); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a const reference to the element at with specified key @a key, + with bounds checking. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if the JSON value is not an object; example: + `"cannot use at() with boolean"` + @throw std::out_of_range if the key @a key is is not stored in the object; + that is, `find(key) == end()`; example: `"key "the fast" not found"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + `at()`.,at__object_t_key_type_const} + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + const_reference at(const typename object_t::key_type& key) const + { + // at only works for objects + if (is_object()) + { + JSON_TRY + { + return m_value.object->at(key); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(std::out_of_range("key '" + key + "' not found")); + } + } + else + { + JSON_THROW(std::domain_error("cannot use at() with " + type_name())); + } + } + + /*! + @brief access specified array element + + Returns a reference to the element at specified location @a idx. + + @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), + then the array is silently filled up with `null` values to make `idx` a + valid reference to the last stored element. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw std::domain_error if JSON is not an array or null; example: + `"cannot use operator[] with string"` + + @complexity Constant if @a idx is in the range of the array. Otherwise + linear in `idx - size()`. + + @liveexample{The example below shows how array elements can be read and + written using `[]` operator. Note the addition of `null` + values.,operatorarray__size_type} + + @since version 1.0.0 + */ + reference operator[](size_type idx) + { + // implicitly convert null value to an empty array + if (is_null()) + { + m_type = value_t::array; + m_value.array = create(); + assert_invariant(); + } + + // operator[] only works for arrays + if (is_array()) + { + // fill up array with null values if given idx is outside range + if (idx >= m_value.array->size()) + { + m_value.array->insert(m_value.array->end(), + idx - m_value.array->size() + 1, + basic_json()); + } + + return m_value.array->operator[](idx); + } + + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + } + + /*! + @brief access specified array element + + Returns a const reference to the element at specified location @a idx. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw std::domain_error if JSON is not an array; example: `"cannot use + operator[] with null"` + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + the `[]` operator.,operatorarray__size_type_const} + + @since version 1.0.0 + */ + const_reference operator[](size_type idx) const + { + // const operator[] only works for arrays + if (is_array()) + { + return m_value.array->operator[](idx); + } + + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with string"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + reference operator[](const typename object_t::key_type& key) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + // operator[] only works for objects + if (is_object()) + { + return m_value.object->operator[](key); + } + + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw std::domain_error if JSON is not an object; example: `"cannot use + operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + const_reference operator[](const typename object_t::key_type& key) const + { + // const operator[] only works for objects + if (is_object()) + { + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with string"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + template + reference operator[](T * (&key)[n]) + { + return operator[](static_cast(key)); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @note This function is required for compatibility reasons with Clang. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object; example: `"cannot use + operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + template + const_reference operator[](T * (&key)[n]) const + { + return operator[](static_cast(key)); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with string"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + reference operator[](T* key) + { + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // at only works for objects + if (is_object()) + { + return m_value.object->operator[](key); + } + + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw std::domain_error if JSON is not an object; example: `"cannot use + operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + const_reference operator[](T* key) const + { + // at only works for objects + if (is_object()) + { + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); + } + + /*! + @brief access specified object element with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(key); + } catch(std::out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const typename object_t::key_type&), this function + does not throw if the given key @a key was not found. + + @note Unlike @ref operator[](const typename object_t::key_type& key), this + function does not implicitly add an element to the position defined by @a + key. This function is furthermore also applicable to const objects. + + @param[in] key key of the element to access + @param[in] default_value the value to return if @a key is not found + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw std::domain_error if JSON is not an object; example: `"cannot use + value() with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + + @since version 1.0.0 + */ + template::value, int>::type = 0> + ValueType value(const typename object_t::key_type& key, ValueType default_value) const + { + // at only works for objects + if (is_object()) + { + // if key is found, return value and given default value otherwise + const auto it = find(key); + if (it != end()) + { + return *it; + } + + return default_value; + } + else + { + JSON_THROW(std::domain_error("cannot use value() with " + type_name())); + } + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const + */ + string_t value(const typename object_t::key_type& key, const char* default_value) const + { + return value(key, string_t(default_value)); + } + + /*! + @brief access specified object element via JSON Pointer with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(ptr); + } catch(std::out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const json_pointer&), this function does not throw + if the given key @a key was not found. + + @param[in] ptr a JSON pointer to the element to access + @param[in] default_value the value to return if @a ptr found no value + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw std::domain_error if JSON is not an object; example: `"cannot use + value() with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value_ptr} + + @sa @ref operator[](const json_pointer&) for unchecked access by reference + + @since version 2.0.2 + */ + template::value, int>::type = 0> + ValueType value(const json_pointer& ptr, ValueType default_value) const + { + // at only works for objects + if (is_object()) + { + // if pointer resolves a value, return it or use default value + JSON_TRY + { + return ptr.get_checked(this); + } + JSON_CATCH (std::out_of_range&) + { + return default_value; + } + } + + JSON_THROW(std::domain_error("cannot use value() with " + type_name())); + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const json_pointer&, ValueType) const + */ + string_t value(const json_pointer& ptr, const char* default_value) const + { + return value(ptr, string_t(default_value)); + } + + /*! + @brief access the first element + + Returns a reference to the first element in the container. For a JSON + container `c`, the expression `c.front()` is equivalent to `*c.begin()`. + + @return In case of a structured type (array or object), a reference to the + first element is returned. In case of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw std::out_of_range when called on `null` value + + @liveexample{The following code shows an example for `front()`.,front} + + @sa @ref back() -- access the last element + + @since version 1.0.0 + */ + reference front() + { + return *begin(); + } + + /*! + @copydoc basic_json::front() + */ + const_reference front() const + { + return *cbegin(); + } + + /*! + @brief access the last element + + Returns a reference to the last element in the container. For a JSON + container `c`, the expression `c.back()` is equivalent to + @code {.cpp} + auto tmp = c.end(); + --tmp; + return *tmp; + @endcode + + @return In case of a structured type (array or object), a reference to the + last element is returned. In case of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw std::out_of_range when called on `null` value. + + @liveexample{The following code shows an example for `back()`.,back} + + @sa @ref front() -- access the first element + + @since version 1.0.0 + */ + reference back() + { + auto tmp = end(); + --tmp; + return *tmp; + } + + /*! + @copydoc basic_json::back() + */ + const_reference back() const + { + auto tmp = cend(); + --tmp; + return *tmp; + } + + /*! + @brief remove element given an iterator + + Removes the element specified by iterator @a pos. The iterator @a pos must + be valid and dereferenceable. Thus the `end()` iterator (which is valid, + but is not dereferenceable) cannot be used as a value for @a pos. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] pos iterator to the element to remove + @return Iterator following the last removed element. If the iterator @a + pos refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw std::domain_error if called on a `null` value; example: `"cannot + use erase() with null"` + @throw std::domain_error if called on an iterator which does not belong to + the current JSON value; example: `"iterator does not fit current value"` + @throw std::out_of_range if called on a primitive type with invalid + iterator (i.e., any iterator which is not `begin()`); example: `"iterator + out of range"` + + @complexity The complexity depends on the type: + - objects: amortized constant + - arrays: linear in distance between @a pos and the end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType} + + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template::value or + std::is_same::value, int>::type + = 0> + IteratorType erase(IteratorType pos) + { + // make sure iterator fits the current value + if (this != pos.m_object) + { + JSON_THROW(std::domain_error("iterator does not fit current value")); + } + + IteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (not pos.m_it.primitive_iterator.is_begin()) + { + JSON_THROW(std::out_of_range("iterator out of range")); + } + + if (is_string()) + { + AllocatorType alloc; + alloc.destroy(m_value.string); + alloc.deallocate(m_value.string, 1); + m_value.string = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); + break; + } + + default: + { + JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); + } + } + + return result; + } + + /*! + @brief remove elements given an iterator range + + Removes the element specified by the range `[first; last)`. The iterator + @a first does not need to be dereferenceable if `first == last`: erasing + an empty range is a no-op. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] first iterator to the beginning of the range to remove + @param[in] last iterator past the end of the range to remove + @return Iterator following the last removed element. If the iterator @a + second refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw std::domain_error if called on a `null` value; example: `"cannot + use erase() with null"` + @throw std::domain_error if called on iterators which does not belong to + the current JSON value; example: `"iterators do not fit current value"` + @throw std::out_of_range if called on a primitive type with invalid + iterators (i.e., if `first != begin()` and `last != end()`); example: + `"iterators out of range"` + + @complexity The complexity depends on the type: + - objects: `log(size()) + std::distance(first, last)` + - arrays: linear in the distance between @a first and @a last, plus linear + in the distance between @a last and end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType_IteratorType} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template::value or + std::is_same::value, int>::type + = 0> + IteratorType erase(IteratorType first, IteratorType last) + { + // make sure iterator fits the current value + if (this != first.m_object or this != last.m_object) + { + JSON_THROW(std::domain_error("iterators do not fit current value")); + } + + IteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) + { + JSON_THROW(std::out_of_range("iterators out of range")); + } + + if (is_string()) + { + AllocatorType alloc; + alloc.destroy(m_value.string); + alloc.deallocate(m_value.string, 1); + m_value.string = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + default: + { + JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); + } + } + + return result; + } + + /*! + @brief remove element from a JSON object given a key + + Removes elements from a JSON object with the key value @a key. + + @param[in] key value of the elements to remove + + @return Number of elements removed. If @a ObjectType is the default + `std::map` type, the return value will always be `0` (@a key was not + found) or `1` (@a key was found). + + @post References and iterators to the erased elements are invalidated. + Other references and iterators are not affected. + + @throw std::domain_error when called on a type other than JSON object; + example: `"cannot use erase() with null"` + + @complexity `log(size()) + count(key)` + + @liveexample{The example shows the effect of `erase()`.,erase__key_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + size_type erase(const typename object_t::key_type& key) + { + // this erase only works for objects + if (is_object()) + { + return m_value.object->erase(key); + } + + JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); + } + + /*! + @brief remove element from a JSON array given an index + + Removes element from a JSON array at the index @a idx. + + @param[in] idx index of the element to remove + + @throw std::domain_error when called on a type other than JSON array; + example: `"cannot use erase() with null"` + @throw std::out_of_range when `idx >= size()`; example: `"array index 17 + is out of range"` + + @complexity Linear in distance between @a idx and the end of the container. + + @liveexample{The example shows the effect of `erase()`.,erase__size_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + + @since version 1.0.0 + */ + void erase(const size_type idx) + { + // this erase only works for arrays + if (is_array()) + { + if (idx >= size()) + { + JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); + } + + m_value.array->erase(m_value.array->begin() + static_cast(idx)); + } + else + { + JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); + } + } + + /// @} + + + //////////// + // lookup // + //////////// + + /// @name lookup + /// @{ + + /*! + @brief find an element in a JSON object + + Finds an element in a JSON object with key equivalent to @a key. If the + element is not found or the JSON value is not an object, end() is + returned. + + @note This method always returns @ref end() when executed on a JSON type + that is not an object. + + @param[in] key key value of the element to search for + + @return Iterator to an element with key equivalent to @a key. If no such + element is found or the JSON value is not an object, past-the-end (see + @ref end()) iterator is returned. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `find()` is used.,find__key_type} + + @since version 1.0.0 + */ + iterator find(typename object_t::key_type key) + { + auto result = end(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(key); + } + + return result; + } + + /*! + @brief find an element in a JSON object + @copydoc find(typename object_t::key_type) + */ + const_iterator find(typename object_t::key_type key) const + { + auto result = cend(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(key); + } + + return result; + } + + /*! + @brief returns the number of occurrences of a key in a JSON object + + Returns the number of elements with key @a key. If ObjectType is the + default `std::map` type, the return value will always be `0` (@a key was + not found) or `1` (@a key was found). + + @note This method always returns `0` when executed on a JSON type that is + not an object. + + @param[in] key key value of the element to count + + @return Number of elements with key @a key. If the JSON value is not an + object, the return value will be `0`. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `count()` is used.,count} + + @since version 1.0.0 + */ + size_type count(typename object_t::key_type key) const + { + // return 0 for all nonobject types + return is_object() ? m_value.object->count(key) : 0; + } + + /// @} + + + /////////////// + // iterators // + /////////////// + + /// @name iterators + /// @{ + + /*! + @brief returns an iterator to the first element + + Returns an iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `begin()`.,begin} + + @sa @ref cbegin() -- returns a const iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + iterator begin() noexcept + { + iterator result(this); + result.set_begin(); + return result; + } + + /*! + @copydoc basic_json::cbegin() + */ + const_iterator begin() const noexcept + { + return cbegin(); + } + + /*! + @brief returns a const iterator to the first element + + Returns a const iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).begin()`. + + @liveexample{The following code shows an example for `cbegin()`.,cbegin} + + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + const_iterator cbegin() const noexcept + { + const_iterator result(this); + result.set_begin(); + return result; + } + + /*! + @brief returns an iterator to one past the last element + + Returns an iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `end()`.,end} + + @sa @ref cend() -- returns a const iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + iterator end() noexcept + { + iterator result(this); + result.set_end(); + return result; + } + + /*! + @copydoc basic_json::cend() + */ + const_iterator end() const noexcept + { + return cend(); + } + + /*! + @brief returns a const iterator to one past the last element + + Returns a const iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).end()`. + + @liveexample{The following code shows an example for `cend()`.,cend} + + @sa @ref end() -- returns an iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + const_iterator cend() const noexcept + { + const_iterator result(this); + result.set_end(); + return result; + } + + /*! + @brief returns an iterator to the reverse-beginning + + Returns an iterator to the reverse-beginning; that is, the last element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(end())`. + + @liveexample{The following code shows an example for `rbegin()`.,rbegin} + + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + reverse_iterator rbegin() noexcept + { + return reverse_iterator(end()); + } + + /*! + @copydoc basic_json::crbegin() + */ + const_reverse_iterator rbegin() const noexcept + { + return crbegin(); + } + + /*! + @brief returns an iterator to the reverse-end + + Returns an iterator to the reverse-end; that is, one before the first + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(begin())`. + + @liveexample{The following code shows an example for `rend()`.,rend} + + @sa @ref crend() -- returns a const reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + reverse_iterator rend() noexcept + { + return reverse_iterator(begin()); + } + + /*! + @copydoc basic_json::crend() + */ + const_reverse_iterator rend() const noexcept + { + return crend(); + } + + /*! + @brief returns a const reverse iterator to the last element + + Returns a const iterator to the reverse-beginning; that is, the last + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rbegin()`. + + @liveexample{The following code shows an example for `crbegin()`.,crbegin} + + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(cend()); + } + + /*! + @brief returns a const reverse iterator to one before the first + + Returns a const reverse iterator to the reverse-end; that is, one before + the first element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rend()`. + + @liveexample{The following code shows an example for `crend()`.,crend} + + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(cbegin()); + } + + private: + // forward declaration + template class iteration_proxy; + + public: + /*! + @brief wrapper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + @note The name of this function is not yet final and may change in the + future. + */ + static iteration_proxy iterator_wrapper(reference cont) + { + return iteration_proxy(cont); + } + + /*! + @copydoc iterator_wrapper(reference) + */ + static iteration_proxy iterator_wrapper(const_reference cont) + { + return iteration_proxy(cont); + } + + /// @} + + + ////////////// + // capacity // + ////////////// + + /// @name capacity + /// @{ + + /*! + @brief checks whether the container is empty + + Checks if a JSON value has no elements. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `true` + boolean | `false` + string | `false` + number | `false` + object | result of function `object_t::empty()` + array | result of function `array_t::empty()` + + @note This function does not return whether a string stored as JSON value + is empty - it returns whether the JSON container itself is empty which is + false in the case of a string. + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `empty()` functions have constant + complexity. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `begin() == end()`. + + @liveexample{The following code uses `empty()` to check if a JSON + object contains any elements.,empty} + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + bool empty() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return true; + } + + case value_t::array: + { + // delegate call to array_t::empty() + return m_value.array->empty(); + } + + case value_t::object: + { + // delegate call to object_t::empty() + return m_value.object->empty(); + } + + default: + { + // all other types are nonempty + return false; + } + } + } + + /*! + @brief returns the number of elements + + Returns the number of elements in a JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` + boolean | `1` + string | `1` + number | `1` + object | result of function object_t::size() + array | result of function array_t::size() + + @note This function does not return the length of a string stored as JSON + value - it returns the number of elements in the JSON value which is 1 in + the case of a string. + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their size() functions have constant + complexity. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `std::distance(begin(), end())`. + + @liveexample{The following code calls `size()` on the different value + types.,size} + + @sa @ref empty() -- checks whether the container is empty + @sa @ref max_size() -- returns the maximal number of elements + + @since version 1.0.0 + */ + size_type size() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return 0; + } + + case value_t::array: + { + // delegate call to array_t::size() + return m_value.array->size(); + } + + case value_t::object: + { + // delegate call to object_t::size() + return m_value.object->size(); + } + + default: + { + // all other types have size 1 + return 1; + } + } + } + + /*! + @brief returns the maximum possible number of elements + + Returns the maximum number of elements a JSON value is able to hold due to + system or library implementation limitations, i.e. `std::distance(begin(), + end())` for the JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` (same as `size()`) + boolean | `1` (same as `size()`) + string | `1` (same as `size()`) + number | `1` (same as `size()`) + object | result of function `object_t::max_size()` + array | result of function `array_t::max_size()` + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `max_size()` functions have constant + complexity. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of returning `b.size()` where `b` is the largest + possible JSON value. + + @liveexample{The following code calls `max_size()` on the different value + types. Note the output is implementation specific.,max_size} + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + size_type max_size() const noexcept + { + switch (m_type) + { + case value_t::array: + { + // delegate call to array_t::max_size() + return m_value.array->max_size(); + } + + case value_t::object: + { + // delegate call to object_t::max_size() + return m_value.object->max_size(); + } + + default: + { + // all other types have max_size() == size() + return size(); + } + } + } + + /// @} + + + /////////////// + // modifiers // + /////////////// + + /// @name modifiers + /// @{ + + /*! + @brief clears the contents + + Clears the content of a JSON value and resets it to the default value as + if @ref basic_json(value_t) would have been called: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows the effect of `clear()` to different + JSON types.,clear} + + @since version 1.0.0 + */ + void clear() noexcept + { + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = 0; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = 0; + break; + } + + case value_t::number_float: + { + m_value.number_float = 0.0; + break; + } + + case value_t::boolean: + { + m_value.boolean = false; + break; + } + + case value_t::string: + { + m_value.string->clear(); + break; + } + + case value_t::array: + { + m_value.array->clear(); + break; + } + + case value_t::object: + { + m_value.object->clear(); + break; + } + + default: + { + break; + } + } + } + + /*! + @brief add an object to an array + + Appends the given element @a val to the end of the JSON value. If the + function is called on a JSON null value, an empty array is created before + appending @a val. + + @param[in] val the value to add to the JSON array + + @throw std::domain_error when called on a type other than JSON array or + null; example: `"cannot use push_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON array. Note how the `null` value was silently + converted to a JSON array.,push_back} + + @since version 1.0.0 + */ + void push_back(basic_json&& val) + { + // push_back only works for null objects or arrays + if (not(is_null() or is_array())) + { + JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array (move semantics) + m_value.array->push_back(std::move(val)); + // invalidate object + val.m_type = value_t::null; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(basic_json&& val) + { + push_back(std::move(val)); + return *this; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + void push_back(const basic_json& val) + { + // push_back only works for null objects or arrays + if (not(is_null() or is_array())) + { + JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array + m_value.array->push_back(val); + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(const basic_json& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + Inserts the given element @a val to the JSON object. If the function is + called on a JSON null value, an empty object is created before inserting + @a val. + + @param[in] val the value to add to the JSON object + + @throw std::domain_error when called on a type other than JSON object or + null; example: `"cannot use push_back() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON object. Note how the `null` value was silently + converted to a JSON object.,push_back__object_t__value} + + @since version 1.0.0 + */ + void push_back(const typename object_t::value_type& val) + { + // push_back only works for null objects or objects + if (not(is_null() or is_object())) + { + JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // add element to array + m_value.object->insert(val); + } + + /*! + @brief add an object to an object + @copydoc push_back(const typename object_t::value_type&) + */ + reference operator+=(const typename object_t::value_type& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + This function allows to use `push_back` with an initializer list. In case + + 1. the current value is an object, + 2. the initializer list @a init contains only two elements, and + 3. the first element of @a init is a string, + + @a init is converted into an object element and added using + @ref push_back(const typename object_t::value_type&). Otherwise, @a init + is converted to a JSON value and added using @ref push_back(basic_json&&). + + @param init an initializer list + + @complexity Linear in the size of the initializer list @a init. + + @note This function is required to resolve an ambiguous overload error, + because pairs like `{"key", "value"}` can be both interpreted as + `object_t::value_type` or `std::initializer_list`, see + https://github.com/nlohmann/json/issues/235 for more information. + + @liveexample{The example shows how initializer lists are treated as + objects when possible.,push_back__initializer_list} + */ + void push_back(std::initializer_list init) + { + if (is_object() and init.size() == 2 and init.begin()->is_string()) + { + const string_t key = *init.begin(); + push_back(typename object_t::value_type(key, *(init.begin() + 1))); + } + else + { + push_back(basic_json(init)); + } + } + + /*! + @brief add an object to an object + @copydoc push_back(std::initializer_list) + */ + reference operator+=(std::initializer_list init) + { + push_back(init); + return *this; + } + + /*! + @brief add an object to an array + + Creates a JSON value from the passed parameters @a args to the end of the + JSON value. If the function is called on a JSON null value, an empty array + is created before appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @throw std::domain_error when called on a type other than JSON array or + null; example: `"cannot use emplace_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` can be used to add + elements to a JSON array. Note how the `null` value was silently converted + to a JSON array.,emplace_back} + + @since version 2.0.8 + */ + template + void emplace_back(Args&& ... args) + { + // emplace_back only works for null objects or arrays + if (not(is_null() or is_array())) + { + JSON_THROW(std::domain_error("cannot use emplace_back() with " + type_name())); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array (perfect forwarding) + m_value.array->emplace_back(std::forward(args)...); + } + + /*! + @brief add an object to an object if key does not exist + + Inserts a new element into a JSON object constructed in-place with the + given @a args if there is no element with the key in the container. If the + function is called on a JSON null value, an empty object is created before + appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @return a pair consisting of an iterator to the inserted element, or the + already-existing element if no insertion happened, and a bool + denoting whether the insertion took place. + + @throw std::domain_error when called on a type other than JSON object or + null; example: `"cannot use emplace() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `emplace()` can be used to add elements + to a JSON object. Note how the `null` value was silently converted to a + JSON object. Further note how no value is added if there was already one + value stored with the same key.,emplace} + + @since version 2.0.8 + */ + template + std::pair emplace(Args&& ... args) + { + // emplace only works for null objects or arrays + if (not(is_null() or is_object())) + { + JSON_THROW(std::domain_error("cannot use emplace() with " + type_name())); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // add element to array (perfect forwarding) + auto res = m_value.object->emplace(std::forward(args)...); + // create result iterator and set iterator to the result of emplace + auto it = begin(); + it.m_it.object_iterator = res.first; + + // return pair of iterator and boolean + return {it, res.second}; + } + + /*! + @brief inserts element + + Inserts element @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] val element to insert + @return iterator pointing to the inserted @a val. + + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` + + @complexity Constant plus linear in the distance between @a pos and end of + the container. + + @liveexample{The example shows how `insert()` is used.,insert} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const basic_json& val) + { + // insert only works for arrays + if (is_array()) + { + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + JSON_THROW(std::domain_error("iterator does not fit current value")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); + return result; + } + + JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); + } + + /*! + @brief inserts element + @copydoc insert(const_iterator, const basic_json&) + */ + iterator insert(const_iterator pos, basic_json&& val) + { + return insert(pos, val); + } + + /*! + @brief inserts elements + + Inserts @a cnt copies of @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] cnt number of copies of @a val to insert + @param[in] val element to insert + @return iterator pointing to the first element inserted, or @a pos if + `cnt==0` + + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` + + @complexity Linear in @a cnt plus linear in the distance between @a pos + and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__count} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, size_type cnt, const basic_json& val) + { + // insert only works for arrays + if (is_array()) + { + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + JSON_THROW(std::domain_error("iterator does not fit current value")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + return result; + } + + JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)` before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` + @throw std::domain_error if @a first and @a last do not belong to the same + JSON value; example: `"iterators do not fit"` + @throw std::domain_error if @a first or @a last are iterators into + container for which insert is called; example: `"passed iterators may not + belong to container"` + + @return iterator pointing to the first element inserted, or @a pos if + `first==last` + + @complexity Linear in `std::distance(first, last)` plus linear in the + distance between @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__range} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const_iterator first, const_iterator last) + { + // insert only works for arrays + if (not is_array()) + { + JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); + } + + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + JSON_THROW(std::domain_error("iterator does not fit current value")); + } + + // check if range iterators belong to the same JSON object + if (first.m_object != last.m_object) + { + JSON_THROW(std::domain_error("iterators do not fit")); + } + + if (first.m_object == this or last.m_object == this) + { + JSON_THROW(std::domain_error("passed iterators may not belong to container")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert( + pos.m_it.array_iterator, + first.m_it.array_iterator, + last.m_it.array_iterator); + return result; + } + + /*! + @brief inserts elements + + Inserts elements from initializer list @a ilist before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] ilist initializer list to insert the values from + + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` + + @return iterator pointing to the first element inserted, or @a pos if + `ilist` is empty + + @complexity Linear in `ilist.size()` plus linear in the distance between + @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__ilist} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, std::initializer_list ilist) + { + // insert only works for arrays + if (not is_array()) + { + JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); + } + + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + JSON_THROW(std::domain_error("iterator does not fit current value")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist); + return result; + } + + /*! + @brief exchanges the values + + Exchanges the contents of the JSON value with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ + void swap(reference other) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + std::swap(m_type, other.m_type); + std::swap(m_value, other.m_value); + assert_invariant(); + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON array with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other array to exchange the contents with + + @throw std::domain_error when JSON value is not an array; example: + `"cannot use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how arrays can be swapped with + `swap()`.,swap__array_t} + + @since version 1.0.0 + */ + void swap(array_t& other) + { + // swap only works for arrays + if (is_array()) + { + std::swap(*(m_value.array), other); + } + else + { + JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON object with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other object to exchange the contents with + + @throw std::domain_error when JSON value is not an object; example: + `"cannot use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how objects can be swapped with + `swap()`.,swap__object_t} + + @since version 1.0.0 + */ + void swap(object_t& other) + { + // swap only works for objects + if (is_object()) + { + std::swap(*(m_value.object), other); + } + else + { + JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON string with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other string to exchange the contents with + + @throw std::domain_error when JSON value is not a string; example: `"cannot + use swap() with boolean"` + + @complexity Constant. + + @liveexample{The example below shows how strings can be swapped with + `swap()`.,swap__string_t} + + @since version 1.0.0 + */ + void swap(string_t& other) + { + // swap only works for strings + if (is_string()) + { + std::swap(*(m_value.string), other); + } + else + { + JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); + } + } + + /// @} + + public: + ////////////////////////////////////////// + // lexicographical comparison operators // + ////////////////////////////////////////// + + /// @name lexicographical comparison operators + /// @{ + + /*! + @brief comparison: equal + + Compares two JSON values for equality according to the following rules: + - Two JSON values are equal if (1) they are from the same type and (2) + their stored values are the same. + - Integer and floating-point numbers are automatically converted before + comparison. Floating-point numbers are compared indirectly: two + floating-point numbers `f1` and `f2` are considered equal if neither + `f1 > f2` nor `f2 > f1` holds. + - Two JSON null values are equal. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are equal + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__equal} + + @since version 1.0.0 + */ + friend bool operator==(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + { + return *lhs.m_value.array == *rhs.m_value.array; + } + case value_t::object: + { + return *lhs.m_value.object == *rhs.m_value.object; + } + case value_t::null: + { + return true; + } + case value_t::string: + { + return *lhs.m_value.string == *rhs.m_value.string; + } + case value_t::boolean: + { + return lhs.m_value.boolean == rhs.m_value.boolean; + } + case value_t::number_integer: + { + return lhs.m_value.number_integer == rhs.m_value.number_integer; + } + case value_t::number_unsigned: + { + return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; + } + case value_t::number_float: + { + return lhs.m_value.number_float == rhs.m_value.number_float; + } + default: + { + return false; + } + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned); + } + + return false; + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs == basic_json(rhs)); + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) == rhs); + } + + /*! + @brief comparison: not equal + + Compares two JSON values for inequality by calculating `not (lhs == rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are not equal + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__notequal} + + @since version 1.0.0 + */ + friend bool operator!=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs == rhs); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs != basic_json(rhs)); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) != rhs); + } + + /*! + @brief comparison: less than + + Compares whether one JSON value @a lhs is less than another JSON value @a + rhs according to the following rules: + - If @a lhs and @a rhs have the same type, the values are compared using + the default `<` operator. + - Integer and floating-point numbers are automatically converted before + comparison + - In case @a lhs and @a rhs have different types, the values are ignored + and the order of the types is considered, see + @ref operator<(const value_t, const value_t). + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__less} + + @since version 1.0.0 + */ + friend bool operator<(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + { + return *lhs.m_value.array < *rhs.m_value.array; + } + case value_t::object: + { + return *lhs.m_value.object < *rhs.m_value.object; + } + case value_t::null: + { + return false; + } + case value_t::string: + { + return *lhs.m_value.string < *rhs.m_value.string; + } + case value_t::boolean: + { + return lhs.m_value.boolean < rhs.m_value.boolean; + } + case value_t::number_integer: + { + return lhs.m_value.number_integer < rhs.m_value.number_integer; + } + case value_t::number_unsigned: + { + return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; + } + case value_t::number_float: + { + return lhs.m_value.number_float < rhs.m_value.number_float; + } + default: + { + return false; + } + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; + } + + // We only reach this line if we cannot compare values. In that case, + // we compare types. Note we have to call the operator explicitly, + // because MSVC has problems otherwise. + return operator<(lhs_type, rhs_type); + } + + /*! + @brief comparison: less than or equal + + Compares whether one JSON value @a lhs is less than or equal to another + JSON value by calculating `not (rhs < lhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than or equal to @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greater} + + @since version 1.0.0 + */ + friend bool operator<=(const_reference lhs, const_reference rhs) noexcept + { + return not (rhs < lhs); + } + + /*! + @brief comparison: greater than + + Compares whether one JSON value @a lhs is greater than another + JSON value by calculating `not (lhs <= rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than to @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__lessequal} + + @since version 1.0.0 + */ + friend bool operator>(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs <= rhs); + } + + /*! + @brief comparison: greater than or equal + + Compares whether one JSON value @a lhs is greater than or equal to another + JSON value by calculating `not (lhs < rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than or equal to @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greaterequal} + + @since version 1.0.0 + */ + friend bool operator>=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs < rhs); + } + + /// @} + + + /////////////////// + // serialization // + /////////////////// + + /// @name serialization + /// @{ + + /*! + @brief serialize to stream + + Serialize the given JSON value @a j to the output stream @a o. The JSON + value will be serialized using the @ref dump member function. The + indentation of the output can be controlled with the member variable + `width` of the output stream @a o. For instance, using the manipulator + `std::setw(4)` on @a o sets the indentation level to `4` and the + serialization result is the same as calling `dump(4)`. + + @param[in,out] o stream to serialize to + @param[in] j JSON value to serialize + + @return the stream @a o + + @complexity Linear. + + @liveexample{The example below shows the serialization with different + parameters to `width` to adjust the indentation level.,operator_serialize} + + @since version 1.0.0 + */ + friend std::ostream& operator<<(std::ostream& o, const basic_json& j) + { + // read width member and use it as indentation parameter if nonzero + const bool pretty_print = (o.width() > 0); + const auto indentation = (pretty_print ? o.width() : 0); + + // reset width to 0 for subsequent calls to this stream + o.width(0); + + // do the actual serialization + j.dump(o, pretty_print, static_cast(indentation)); + + return o; + } + + /*! + @brief serialize to stream + @copydoc operator<<(std::ostream&, const basic_json&) + */ + friend std::ostream& operator>>(const basic_json& j, std::ostream& o) + { + return o << j; + } + + /// @} + + + ///////////////////// + // deserialization // + ///////////////////// + + /// @name deserialization + /// @{ + + /*! + @brief deserialize from an array + + This function reads from an array of 1-byte values. + + @pre Each element of the container has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @param[in] array array to read from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an array.,parse__array__parser_callback_t} + + @since version 2.0.3 + */ + template + static basic_json parse(T (&array)[N], + const parser_callback_t cb = nullptr) + { + // delegate the call to the iterator-range parse overload + return parse(std::begin(array), std::end(array), cb); + } + + /*! + @brief deserialize from string literal + + @tparam CharT character/literal type with size of 1 byte + @param[in] s string literal to read a serialized JSON value from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + @note String containers like `std::string` or @ref string_t can be parsed + with @ref parse(const ContiguousContainer&, const parser_callback_t) + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__string__parser_callback_t} + + @sa @ref parse(std::istream&, const parser_callback_t) for a version that + reads from an input stream + + @since version 1.0.0 (originally for @ref string_t) + */ + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, int>::type = 0> + static basic_json parse(const CharT s, + const parser_callback_t cb = nullptr) + { + return parser(reinterpret_cast(s), cb).parse(); + } + + /*! + @brief deserialize from stream + + @param[in,out] i stream to read a serialized JSON value from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__istream__parser_callback_t} + + @sa @ref parse(const CharT, const parser_callback_t) for a version + that reads from a string + + @since version 1.0.0 + */ + static basic_json parse(std::istream& i, + const parser_callback_t cb = nullptr) + { + return parser(i, cb).parse(); + } + + /*! + @copydoc parse(std::istream&, const parser_callback_t) + */ + static basic_json parse(std::istream&& i, + const parser_callback_t cb = nullptr) + { + return parser(i, cb).parse(); + } + + /*! + @brief deserialize from an iterator range with contiguous storage + + This function reads from an iterator range of a container with contiguous + storage of 1-byte values. Compatible container types include + `std::vector`, `std::string`, `std::array`, `std::valarray`, and + `std::initializer_list`. Furthermore, C-style arrays can be used with + `std::begin()`/`std::end()`. User-defined containers can be used as long + as they implement random-access iterators and a contiguous storage. + + @pre The iterator range is contiguous. Violating this precondition yields + undefined behavior. **This precondition is enforced with an assertion.** + @pre Each element in the range has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @warning There is no way to enforce all preconditions at compile-time. If + the function is called with noncompliant iterators and with + assertions switched off, the behavior is undefined and will most + likely yield segmentation violation. + + @tparam IteratorType iterator of container with contiguous storage + @param[in] first begin of the range to parse (included) + @param[in] last end of the range to parse (excluded) + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an iterator range.,parse__iteratortype__parser_callback_t} + + @since version 2.0.3 + */ + template::iterator_category>::value, int>::type = 0> + static basic_json parse(IteratorType first, IteratorType last, + const parser_callback_t cb = nullptr) + { + // assertion to check that the iterator range is indeed contiguous, + // see http://stackoverflow.com/a/35008842/266378 for more discussion + assert(std::accumulate(first, last, std::pair(true, 0), + [&first](std::pair res, decltype(*first) val) + { + res.first &= (val == *(std::next(std::addressof(*first), res.second++))); + return res; + }).first); + + // assertion to check that each element is 1 byte long + static_assert(sizeof(typename std::iterator_traits::value_type) == 1, + "each element in the iterator range must have the size of 1 byte"); + + // if iterator range is empty, create a parser with an empty string + // to generate "unexpected EOF" error message + if (std::distance(first, last) <= 0) + { + return parser("").parse(); + } + + return parser(first, last, cb).parse(); + } + + /*! + @brief deserialize from a container with contiguous storage + + This function reads from a container with contiguous storage of 1-byte + values. Compatible container types include `std::vector`, `std::string`, + `std::array`, and `std::initializer_list`. User-defined containers can be + used as long as they implement random-access iterators and a contiguous + storage. + + @pre The container storage is contiguous. Violating this precondition + yields undefined behavior. **This precondition is enforced with an + assertion.** + @pre Each element of the container has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @warning There is no way to enforce all preconditions at compile-time. If + the function is called with a noncompliant container and with + assertions switched off, the behavior is undefined and will most + likely yield segmentation violation. + + @tparam ContiguousContainer container type with contiguous storage + @param[in] c container to read from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from a contiguous container.,parse__contiguouscontainer__parser_callback_t} + + @since version 2.0.3 + */ + template::value and + std::is_base_of< + std::random_access_iterator_tag, + typename std::iterator_traits()))>::iterator_category>::value + , int>::type = 0> + static basic_json parse(const ContiguousContainer& c, + const parser_callback_t cb = nullptr) + { + // delegate the call to the iterator-range parse overload + return parse(std::begin(c), std::end(c), cb); + } + + /*! + @brief deserialize from stream + + Deserializes an input stream to a JSON value. + + @param[in,out] i input stream to read a serialized JSON value from + @param[in,out] j JSON value to write the deserialized input to + + @throw std::invalid_argument in case of parse errors + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below shows how a JSON value is constructed by + reading a serialization from a stream.,operator_deserialize} + + @sa parse(std::istream&, const parser_callback_t) for a variant with a + parser callback function to filter values while parsing + + @since version 1.0.0 + */ + friend std::istream& operator<<(basic_json& j, std::istream& i) + { + j = parser(i).parse(); + return i; + } + + /*! + @brief deserialize from stream + @copydoc operator<<(basic_json&, std::istream&) + */ + friend std::istream& operator>>(std::istream& i, basic_json& j) + { + j = parser(i).parse(); + return i; + } + + /// @} + + ////////////////////////////////////////// + // binary serialization/deserialization // + ////////////////////////////////////////// + + /// @name binary serialization/deserialization support + /// @{ + + private: + /*! + @note Some code in the switch cases has been copied, because otherwise + copilers would complain about implicit fallthrough and there is no + portable attribute to mute such warnings. + */ + template + static void add_to_vector(std::vector& vec, size_t bytes, const T number) + { + assert(bytes == 1 or bytes == 2 or bytes == 4 or bytes == 8); + + switch (bytes) + { + case 8: + { + vec.push_back(static_cast((static_cast(number) >> 070) & 0xff)); + vec.push_back(static_cast((static_cast(number) >> 060) & 0xff)); + vec.push_back(static_cast((static_cast(number) >> 050) & 0xff)); + vec.push_back(static_cast((static_cast(number) >> 040) & 0xff)); + vec.push_back(static_cast((number >> 030) & 0xff)); + vec.push_back(static_cast((number >> 020) & 0xff)); + vec.push_back(static_cast((number >> 010) & 0xff)); + vec.push_back(static_cast(number & 0xff)); + break; + } + + case 4: + { + vec.push_back(static_cast((number >> 030) & 0xff)); + vec.push_back(static_cast((number >> 020) & 0xff)); + vec.push_back(static_cast((number >> 010) & 0xff)); + vec.push_back(static_cast(number & 0xff)); + break; + } + + case 2: + { + vec.push_back(static_cast((number >> 010) & 0xff)); + vec.push_back(static_cast(number & 0xff)); + break; + } + + case 1: + { + vec.push_back(static_cast(number & 0xff)); + break; + } + } + } + + /*! + @brief take sufficient bytes from a vector to fill an integer variable + + In the context of binary serialization formats, we need to read several + bytes from a byte vector and combine them to multi-byte integral data + types. + + @param[in] vec byte vector to read from + @param[in] current_index the position in the vector after which to read + + @return the next sizeof(T) bytes from @a vec, in reverse order as T + + @tparam T the integral return type + + @throw std::out_of_range if there are less than sizeof(T)+1 bytes in the + vector @a vec to read + + In the for loop, the bytes from the vector are copied in reverse order into + the return value. In the figures below, let sizeof(T)=4 and `i` be the loop + variable. + + Precondition: + + vec: | | | a | b | c | d | T: | | | | | + ^ ^ ^ ^ + current_index i ptr sizeof(T) + + Postcondition: + + vec: | | | a | b | c | d | T: | d | c | b | a | + ^ ^ ^ + | i ptr + current_index + + @sa Code adapted from . + */ + template + static T get_from_vector(const std::vector& vec, const size_t current_index) + { + if (current_index + sizeof(T) + 1 > vec.size()) + { + JSON_THROW(std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector")); + } + + T result; + auto* ptr = reinterpret_cast(&result); + for (size_t i = 0; i < sizeof(T); ++i) + { + *ptr++ = vec[current_index + sizeof(T) - i]; + } + return result; + } + + /*! + @brief create a MessagePack serialization of a given JSON value + + This is a straightforward implementation of the MessagePack specification. + + @param[in] j JSON value to serialize + @param[in,out] v byte vector to write the serialization to + + @sa https://github.com/msgpack/msgpack/blob/master/spec.md + */ + static void to_msgpack_internal(const basic_json& j, std::vector& v) + { + switch (j.type()) + { + case value_t::null: + { + // nil + v.push_back(0xc0); + break; + } + + case value_t::boolean: + { + // true and false + v.push_back(j.m_value.boolean ? 0xc3 : 0xc2); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // MessagePack does not differentiate between positive + // signed integers and unsigned integers. Therefore, we + // used the code from the value_t::number_unsigned case + // here. + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + add_to_vector(v, 1, j.m_value.number_unsigned); + } + else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + { + // uint 8 + v.push_back(0xcc); + add_to_vector(v, 1, j.m_value.number_unsigned); + } + else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + { + // uint 16 + v.push_back(0xcd); + add_to_vector(v, 2, j.m_value.number_unsigned); + } + else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + { + // uint 32 + v.push_back(0xce); + add_to_vector(v, 4, j.m_value.number_unsigned); + } + else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + { + // uint 64 + v.push_back(0xcf); + add_to_vector(v, 8, j.m_value.number_unsigned); + } + } + else + { + if (j.m_value.number_integer >= -32) + { + // negative fixnum + add_to_vector(v, 1, j.m_value.number_integer); + } + else if (j.m_value.number_integer >= std::numeric_limits::min() and j.m_value.number_integer <= std::numeric_limits::max()) + { + // int 8 + v.push_back(0xd0); + add_to_vector(v, 1, j.m_value.number_integer); + } + else if (j.m_value.number_integer >= std::numeric_limits::min() and j.m_value.number_integer <= std::numeric_limits::max()) + { + // int 16 + v.push_back(0xd1); + add_to_vector(v, 2, j.m_value.number_integer); + } + else if (j.m_value.number_integer >= std::numeric_limits::min() and j.m_value.number_integer <= std::numeric_limits::max()) + { + // int 32 + v.push_back(0xd2); + add_to_vector(v, 4, j.m_value.number_integer); + } + else if (j.m_value.number_integer >= std::numeric_limits::min() and j.m_value.number_integer <= std::numeric_limits::max()) + { + // int 64 + v.push_back(0xd3); + add_to_vector(v, 8, j.m_value.number_integer); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + add_to_vector(v, 1, j.m_value.number_unsigned); + } + else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + { + // uint 8 + v.push_back(0xcc); + add_to_vector(v, 1, j.m_value.number_unsigned); + } + else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + { + // uint 16 + v.push_back(0xcd); + add_to_vector(v, 2, j.m_value.number_unsigned); + } + else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + { + // uint 32 + v.push_back(0xce); + add_to_vector(v, 4, j.m_value.number_unsigned); + } + else if (j.m_value.number_unsigned <= std::numeric_limits::max()) + { + // uint 64 + v.push_back(0xcf); + add_to_vector(v, 8, j.m_value.number_unsigned); + } + break; + } + + case value_t::number_float: + { + // float 64 + v.push_back(0xcb); + const auto* helper = reinterpret_cast(&(j.m_value.number_float)); + for (size_t i = 0; i < 8; ++i) + { + v.push_back(helper[7 - i]); + } + break; + } + + case value_t::string: + { + const auto N = j.m_value.string->size(); + if (N <= 31) + { + // fixstr + v.push_back(static_cast(0xa0 | N)); + } + else if (N <= 255) + { + // str 8 + v.push_back(0xd9); + add_to_vector(v, 1, N); + } + else if (N <= 65535) + { + // str 16 + v.push_back(0xda); + add_to_vector(v, 2, N); + } + else if (N <= 4294967295) + { + // str 32 + v.push_back(0xdb); + add_to_vector(v, 4, N); + } + + // append string + std::copy(j.m_value.string->begin(), j.m_value.string->end(), + std::back_inserter(v)); + break; + } + + case value_t::array: + { + const auto N = j.m_value.array->size(); + if (N <= 15) + { + // fixarray + v.push_back(static_cast(0x90 | N)); + } + else if (N <= 0xffff) + { + // array 16 + v.push_back(0xdc); + add_to_vector(v, 2, N); + } + else if (N <= 0xffffffff) + { + // array 32 + v.push_back(0xdd); + add_to_vector(v, 4, N); + } + + // append each element + for (const auto& el : *j.m_value.array) + { + to_msgpack_internal(el, v); + } + break; + } + + case value_t::object: + { + const auto N = j.m_value.object->size(); + if (N <= 15) + { + // fixmap + v.push_back(static_cast(0x80 | (N & 0xf))); + } + else if (N <= 65535) + { + // map 16 + v.push_back(0xde); + add_to_vector(v, 2, N); + } + else if (N <= 4294967295) + { + // map 32 + v.push_back(0xdf); + add_to_vector(v, 4, N); + } + + // append each element + for (const auto& el : *j.m_value.object) + { + to_msgpack_internal(el.first, v); + to_msgpack_internal(el.second, v); + } + break; + } + + default: + { + break; + } + } + } + + /*! + @brief create a CBOR serialization of a given JSON value + + This is a straightforward implementation of the CBOR specification. + + @param[in] j JSON value to serialize + @param[in,out] v byte vector to write the serialization to + + @sa https://tools.ietf.org/html/rfc7049 + */ + static void to_cbor_internal(const basic_json& j, std::vector& v) + { + switch (j.type()) + { + case value_t::null: + { + v.push_back(0xf6); + break; + } + + case value_t::boolean: + { + v.push_back(j.m_value.boolean ? 0xf5 : 0xf4); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // CBOR does not differentiate between positive signed + // integers and unsigned integers. Therefore, we used the + // code from the value_t::number_unsigned case here. + if (j.m_value.number_integer <= 0x17) + { + add_to_vector(v, 1, j.m_value.number_integer); + } + else if (j.m_value.number_integer <= std::numeric_limits::max()) + { + v.push_back(0x18); + // one-byte uint8_t + add_to_vector(v, 1, j.m_value.number_integer); + } + else if (j.m_value.number_integer <= std::numeric_limits::max()) + { + v.push_back(0x19); + // two-byte uint16_t + add_to_vector(v, 2, j.m_value.number_integer); + } + else if (j.m_value.number_integer <= std::numeric_limits::max()) + { + v.push_back(0x1a); + // four-byte uint32_t + add_to_vector(v, 4, j.m_value.number_integer); + } + else + { + v.push_back(0x1b); + // eight-byte uint64_t + add_to_vector(v, 8, j.m_value.number_integer); + } + } + else + { + // The conversions below encode the sign in the first + // byte, and the value is converted to a positive number. + const auto positive_number = -1 - j.m_value.number_integer; + if (j.m_value.number_integer >= -24) + { + v.push_back(static_cast(0x20 + positive_number)); + } + else if (positive_number <= std::numeric_limits::max()) + { + // int 8 + v.push_back(0x38); + add_to_vector(v, 1, positive_number); + } + else if (positive_number <= std::numeric_limits::max()) + { + // int 16 + v.push_back(0x39); + add_to_vector(v, 2, positive_number); + } + else if (positive_number <= std::numeric_limits::max()) + { + // int 32 + v.push_back(0x3a); + add_to_vector(v, 4, positive_number); + } + else + { + // int 64 + v.push_back(0x3b); + add_to_vector(v, 8, positive_number); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned <= 0x17) + { + v.push_back(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= 0xff) + { + v.push_back(0x18); + // one-byte uint8_t + add_to_vector(v, 1, j.m_value.number_unsigned); + } + else if (j.m_value.number_unsigned <= 0xffff) + { + v.push_back(0x19); + // two-byte uint16_t + add_to_vector(v, 2, j.m_value.number_unsigned); + } + else if (j.m_value.number_unsigned <= 0xffffffff) + { + v.push_back(0x1a); + // four-byte uint32_t + add_to_vector(v, 4, j.m_value.number_unsigned); + } + else if (j.m_value.number_unsigned <= 0xffffffffffffffff) + { + v.push_back(0x1b); + // eight-byte uint64_t + add_to_vector(v, 8, j.m_value.number_unsigned); + } + break; + } + + case value_t::number_float: + { + // Double-Precision Float + v.push_back(0xfb); + const auto* helper = reinterpret_cast(&(j.m_value.number_float)); + for (size_t i = 0; i < 8; ++i) + { + v.push_back(helper[7 - i]); + } + break; + } + + case value_t::string: + { + const auto N = j.m_value.string->size(); + if (N <= 0x17) + { + v.push_back(0x60 + static_cast(N)); // 1 byte for string + size + } + else if (N <= 0xff) + { + v.push_back(0x78); // one-byte uint8_t for N + add_to_vector(v, 1, N); + } + else if (N <= 0xffff) + { + v.push_back(0x79); // two-byte uint16_t for N + add_to_vector(v, 2, N); + } + else if (N <= 0xffffffff) + { + v.push_back(0x7a); // four-byte uint32_t for N + add_to_vector(v, 4, N); + } + // LCOV_EXCL_START + else if (N <= 0xffffffffffffffff) + { + v.push_back(0x7b); // eight-byte uint64_t for N + add_to_vector(v, 8, N); + } + // LCOV_EXCL_STOP + + // append string + std::copy(j.m_value.string->begin(), j.m_value.string->end(), + std::back_inserter(v)); + break; + } + + case value_t::array: + { + const auto N = j.m_value.array->size(); + if (N <= 0x17) + { + v.push_back(0x80 + static_cast(N)); // 1 byte for array + size + } + else if (N <= 0xff) + { + v.push_back(0x98); // one-byte uint8_t for N + add_to_vector(v, 1, N); + } + else if (N <= 0xffff) + { + v.push_back(0x99); // two-byte uint16_t for N + add_to_vector(v, 2, N); + } + else if (N <= 0xffffffff) + { + v.push_back(0x9a); // four-byte uint32_t for N + add_to_vector(v, 4, N); + } + // LCOV_EXCL_START + else if (N <= 0xffffffffffffffff) + { + v.push_back(0x9b); // eight-byte uint64_t for N + add_to_vector(v, 8, N); + } + // LCOV_EXCL_STOP + + // append each element + for (const auto& el : *j.m_value.array) + { + to_cbor_internal(el, v); + } + break; + } + + case value_t::object: + { + const auto N = j.m_value.object->size(); + if (N <= 0x17) + { + v.push_back(0xa0 + static_cast(N)); // 1 byte for object + size + } + else if (N <= 0xff) + { + v.push_back(0xb8); + add_to_vector(v, 1, N); // one-byte uint8_t for N + } + else if (N <= 0xffff) + { + v.push_back(0xb9); + add_to_vector(v, 2, N); // two-byte uint16_t for N + } + else if (N <= 0xffffffff) + { + v.push_back(0xba); + add_to_vector(v, 4, N); // four-byte uint32_t for N + } + // LCOV_EXCL_START + else if (N <= 0xffffffffffffffff) + { + v.push_back(0xbb); + add_to_vector(v, 8, N); // eight-byte uint64_t for N + } + // LCOV_EXCL_STOP + + // append each element + for (const auto& el : *j.m_value.object) + { + to_cbor_internal(el.first, v); + to_cbor_internal(el.second, v); + } + break; + } + + default: + { + break; + } + } + } + + + /* + @brief checks if given lengths do not exceed the size of a given vector + + To secure the access to the byte vector during CBOR/MessagePack + deserialization, bytes are copied from the vector into buffers. This + function checks if the number of bytes to copy (@a len) does not exceed + the size @s size of the vector. Additionally, an @a offset is given from + where to start reading the bytes. + + This function checks whether reading the bytes is safe; that is, offset is + a valid index in the vector, offset+len + + @param[in] size size of the byte vector + @param[in] len number of bytes to read + @param[in] offset offset where to start reading + + vec: x x x x x X X X X X + ^ ^ ^ + 0 offset len + + @throws out_of_range if `len > v.size()` + */ + static void check_length(const size_t size, const size_t len, const size_t offset) + { + // simple case: requested length is greater than the vector's length + if (len > size or offset > size) + { + JSON_THROW(std::out_of_range("len out of range")); + } + + // second case: adding offset would result in overflow + if ((size > (std::numeric_limits::max() - offset))) + { + JSON_THROW(std::out_of_range("len+offset out of range")); + } + + // last case: reading past the end of the vector + if (len + offset > size) + { + JSON_THROW(std::out_of_range("len+offset out of range")); + } + } + + /*! + @brief create a JSON value from a given MessagePack vector + + @param[in] v MessagePack serialization + @param[in] idx byte index to start reading from @a v + + @return deserialized JSON value + + @throw std::invalid_argument if unsupported features from MessagePack were + used in the given vector @a v or if the input is not valid MessagePack + @throw std::out_of_range if the given vector ends prematurely + + @sa https://github.com/msgpack/msgpack/blob/master/spec.md + */ + static basic_json from_msgpack_internal(const std::vector& v, size_t& idx) + { + // make sure reading 1 byte is safe + check_length(v.size(), 1, idx); + + // store and increment index + const size_t current_idx = idx++; + + if (v[current_idx] <= 0xbf) + { + if (v[current_idx] <= 0x7f) // positive fixint + { + return v[current_idx]; + } + if (v[current_idx] <= 0x8f) // fixmap + { + basic_json result = value_t::object; + const size_t len = v[current_idx] & 0x0f; + for (size_t i = 0; i < len; ++i) + { + std::string key = from_msgpack_internal(v, idx); + result[key] = from_msgpack_internal(v, idx); + } + return result; + } + else if (v[current_idx] <= 0x9f) // fixarray + { + basic_json result = value_t::array; + const size_t len = v[current_idx] & 0x0f; + for (size_t i = 0; i < len; ++i) + { + result.push_back(from_msgpack_internal(v, idx)); + } + return result; + } + else // fixstr + { + const size_t len = v[current_idx] & 0x1f; + const size_t offset = current_idx + 1; + idx += len; // skip content bytes + check_length(v.size(), len, offset); + return std::string(reinterpret_cast(v.data()) + offset, len); + } + } + else if (v[current_idx] >= 0xe0) // negative fixint + { + return static_cast(v[current_idx]); + } + else + { + switch (v[current_idx]) + { + case 0xc0: // nil + { + return value_t::null; + } + + case 0xc2: // false + { + return false; + } + + case 0xc3: // true + { + return true; + } + + case 0xca: // float 32 + { + // copy bytes in reverse order into the double variable + float res; + for (size_t byte = 0; byte < sizeof(float); ++byte) + { + reinterpret_cast(&res)[sizeof(float) - byte - 1] = v.at(current_idx + 1 + byte); + } + idx += sizeof(float); // skip content bytes + return res; + } + + case 0xcb: // float 64 + { + // copy bytes in reverse order into the double variable + double res; + for (size_t byte = 0; byte < sizeof(double); ++byte) + { + reinterpret_cast(&res)[sizeof(double) - byte - 1] = v.at(current_idx + 1 + byte); + } + idx += sizeof(double); // skip content bytes + return res; + } + + case 0xcc: // uint 8 + { + idx += 1; // skip content byte + return get_from_vector(v, current_idx); + } + + case 0xcd: // uint 16 + { + idx += 2; // skip 2 content bytes + return get_from_vector(v, current_idx); + } + + case 0xce: // uint 32 + { + idx += 4; // skip 4 content bytes + return get_from_vector(v, current_idx); + } + + case 0xcf: // uint 64 + { + idx += 8; // skip 8 content bytes + return get_from_vector(v, current_idx); + } + + case 0xd0: // int 8 + { + idx += 1; // skip content byte + return get_from_vector(v, current_idx); + } + + case 0xd1: // int 16 + { + idx += 2; // skip 2 content bytes + return get_from_vector(v, current_idx); + } + + case 0xd2: // int 32 + { + idx += 4; // skip 4 content bytes + return get_from_vector(v, current_idx); + } + + case 0xd3: // int 64 + { + idx += 8; // skip 8 content bytes + return get_from_vector(v, current_idx); + } + + case 0xd9: // str 8 + { + const auto len = static_cast(get_from_vector(v, current_idx)); + const size_t offset = current_idx + 2; + idx += len + 1; // skip size byte + content bytes + check_length(v.size(), len, offset); + return std::string(reinterpret_cast(v.data()) + offset, len); + } + + case 0xda: // str 16 + { + const auto len = static_cast(get_from_vector(v, current_idx)); + const size_t offset = current_idx + 3; + idx += len + 2; // skip 2 size bytes + content bytes + check_length(v.size(), len, offset); + return std::string(reinterpret_cast(v.data()) + offset, len); + } + + case 0xdb: // str 32 + { + const auto len = static_cast(get_from_vector(v, current_idx)); + const size_t offset = current_idx + 5; + idx += len + 4; // skip 4 size bytes + content bytes + check_length(v.size(), len, offset); + return std::string(reinterpret_cast(v.data()) + offset, len); + } + + case 0xdc: // array 16 + { + basic_json result = value_t::array; + const auto len = static_cast(get_from_vector(v, current_idx)); + idx += 2; // skip 2 size bytes + for (size_t i = 0; i < len; ++i) + { + result.push_back(from_msgpack_internal(v, idx)); + } + return result; + } + + case 0xdd: // array 32 + { + basic_json result = value_t::array; + const auto len = static_cast(get_from_vector(v, current_idx)); + idx += 4; // skip 4 size bytes + for (size_t i = 0; i < len; ++i) + { + result.push_back(from_msgpack_internal(v, idx)); + } + return result; + } + + case 0xde: // map 16 + { + basic_json result = value_t::object; + const auto len = static_cast(get_from_vector(v, current_idx)); + idx += 2; // skip 2 size bytes + for (size_t i = 0; i < len; ++i) + { + std::string key = from_msgpack_internal(v, idx); + result[key] = from_msgpack_internal(v, idx); + } + return result; + } + + case 0xdf: // map 32 + { + basic_json result = value_t::object; + const auto len = static_cast(get_from_vector(v, current_idx)); + idx += 4; // skip 4 size bytes + for (size_t i = 0; i < len; ++i) + { + std::string key = from_msgpack_internal(v, idx); + result[key] = from_msgpack_internal(v, idx); + } + return result; + } + + default: + { + JSON_THROW(std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast(v[current_idx])))); + } + } + } + } + + /*! + @brief create a JSON value from a given CBOR vector + + @param[in] v CBOR serialization + @param[in] idx byte index to start reading from @a v + + @return deserialized JSON value + + @throw std::invalid_argument if unsupported features from CBOR were used in + the given vector @a v or if the input is not valid CBOR + @throw std::out_of_range if the given vector ends prematurely + + @sa https://tools.ietf.org/html/rfc7049 + */ + static basic_json from_cbor_internal(const std::vector& v, size_t& idx) + { + // store and increment index + const size_t current_idx = idx++; + + switch (v.at(current_idx)) + { + // Integer 0x00..0x17 (0..23) + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + { + return v[current_idx]; + } + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + { + idx += 1; // skip content byte + return get_from_vector(v, current_idx); + } + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + { + idx += 2; // skip 2 content bytes + return get_from_vector(v, current_idx); + } + + case 0x1a: // Unsigned integer (four-byte uint32_t follows) + { + idx += 4; // skip 4 content bytes + return get_from_vector(v, current_idx); + } + + case 0x1b: // Unsigned integer (eight-byte uint64_t follows) + { + idx += 8; // skip 8 content bytes + return get_from_vector(v, current_idx); + } + + // Negative integer -1-0x00..-1-0x17 (-1..-24) + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: + case 0x2c: + case 0x2d: + case 0x2e: + case 0x2f: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + { + return static_cast(0x20 - 1 - v[current_idx]); + } + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + idx += 1; // skip content byte + // must be uint8_t ! + return static_cast(-1) - get_from_vector(v, current_idx); + } + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + idx += 2; // skip 2 content bytes + return static_cast(-1) - get_from_vector(v, current_idx); + } + + case 0x3a: // Negative integer -1-n (four-byte uint32_t follows) + { + idx += 4; // skip 4 content bytes + return static_cast(-1) - get_from_vector(v, current_idx); + } + + case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows) + { + idx += 8; // skip 8 content bytes + return static_cast(-1) - static_cast(get_from_vector(v, current_idx)); + } + + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6a: + case 0x6b: + case 0x6c: + case 0x6d: + case 0x6e: + case 0x6f: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + { + const auto len = static_cast(v[current_idx] - 0x60); + const size_t offset = current_idx + 1; + idx += len; // skip content bytes + check_length(v.size(), len, offset); + return std::string(reinterpret_cast(v.data()) + offset, len); + } + + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + const auto len = static_cast(get_from_vector(v, current_idx)); + const size_t offset = current_idx + 2; + idx += len + 1; // skip size byte + content bytes + check_length(v.size(), len, offset); + return std::string(reinterpret_cast(v.data()) + offset, len); + } + + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + const auto len = static_cast(get_from_vector(v, current_idx)); + const size_t offset = current_idx + 3; + idx += len + 2; // skip 2 size bytes + content bytes + check_length(v.size(), len, offset); + return std::string(reinterpret_cast(v.data()) + offset, len); + } + + case 0x7a: // UTF-8 string (four-byte uint32_t for n follow) + { + const auto len = static_cast(get_from_vector(v, current_idx)); + const size_t offset = current_idx + 5; + idx += len + 4; // skip 4 size bytes + content bytes + check_length(v.size(), len, offset); + return std::string(reinterpret_cast(v.data()) + offset, len); + } + + case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow) + { + const auto len = static_cast(get_from_vector(v, current_idx)); + const size_t offset = current_idx + 9; + idx += len + 8; // skip 8 size bytes + content bytes + check_length(v.size(), len, offset); + return std::string(reinterpret_cast(v.data()) + offset, len); + } + + case 0x7f: // UTF-8 string (indefinite length) + { + std::string result; + while (v.at(idx) != 0xff) + { + string_t s = from_cbor_internal(v, idx); + result += s; + } + // skip break byte (0xFF) + idx += 1; + return result; + } + + // array (0x00..0x17 data items follow) + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8a: + case 0x8b: + case 0x8c: + case 0x8d: + case 0x8e: + case 0x8f: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + { + basic_json result = value_t::array; + const auto len = static_cast(v[current_idx] - 0x80); + for (size_t i = 0; i < len; ++i) + { + result.push_back(from_cbor_internal(v, idx)); + } + return result; + } + + case 0x98: // array (one-byte uint8_t for n follows) + { + basic_json result = value_t::array; + const auto len = static_cast(get_from_vector(v, current_idx)); + idx += 1; // skip 1 size byte + for (size_t i = 0; i < len; ++i) + { + result.push_back(from_cbor_internal(v, idx)); + } + return result; + } + + case 0x99: // array (two-byte uint16_t for n follow) + { + basic_json result = value_t::array; + const auto len = static_cast(get_from_vector(v, current_idx)); + idx += 2; // skip 4 size bytes + for (size_t i = 0; i < len; ++i) + { + result.push_back(from_cbor_internal(v, idx)); + } + return result; + } + + case 0x9a: // array (four-byte uint32_t for n follow) + { + basic_json result = value_t::array; + const auto len = static_cast(get_from_vector(v, current_idx)); + idx += 4; // skip 4 size bytes + for (size_t i = 0; i < len; ++i) + { + result.push_back(from_cbor_internal(v, idx)); + } + return result; + } + + case 0x9b: // array (eight-byte uint64_t for n follow) + { + basic_json result = value_t::array; + const auto len = static_cast(get_from_vector(v, current_idx)); + idx += 8; // skip 8 size bytes + for (size_t i = 0; i < len; ++i) + { + result.push_back(from_cbor_internal(v, idx)); + } + return result; + } + + case 0x9f: // array (indefinite length) + { + basic_json result = value_t::array; + while (v.at(idx) != 0xff) + { + result.push_back(from_cbor_internal(v, idx)); + } + // skip break byte (0xFF) + idx += 1; + return result; + } + + // map (0x00..0x17 pairs of data items follow) + case 0xa0: + case 0xa1: + case 0xa2: + case 0xa3: + case 0xa4: + case 0xa5: + case 0xa6: + case 0xa7: + case 0xa8: + case 0xa9: + case 0xaa: + case 0xab: + case 0xac: + case 0xad: + case 0xae: + case 0xaf: + case 0xb0: + case 0xb1: + case 0xb2: + case 0xb3: + case 0xb4: + case 0xb5: + case 0xb6: + case 0xb7: + { + basic_json result = value_t::object; + const auto len = static_cast(v[current_idx] - 0xa0); + for (size_t i = 0; i < len; ++i) + { + std::string key = from_cbor_internal(v, idx); + result[key] = from_cbor_internal(v, idx); + } + return result; + } + + case 0xb8: // map (one-byte uint8_t for n follows) + { + basic_json result = value_t::object; + const auto len = static_cast(get_from_vector(v, current_idx)); + idx += 1; // skip 1 size byte + for (size_t i = 0; i < len; ++i) + { + std::string key = from_cbor_internal(v, idx); + result[key] = from_cbor_internal(v, idx); + } + return result; + } + + case 0xb9: // map (two-byte uint16_t for n follow) + { + basic_json result = value_t::object; + const auto len = static_cast(get_from_vector(v, current_idx)); + idx += 2; // skip 2 size bytes + for (size_t i = 0; i < len; ++i) + { + std::string key = from_cbor_internal(v, idx); + result[key] = from_cbor_internal(v, idx); + } + return result; + } + + case 0xba: // map (four-byte uint32_t for n follow) + { + basic_json result = value_t::object; + const auto len = static_cast(get_from_vector(v, current_idx)); + idx += 4; // skip 4 size bytes + for (size_t i = 0; i < len; ++i) + { + std::string key = from_cbor_internal(v, idx); + result[key] = from_cbor_internal(v, idx); + } + return result; + } + + case 0xbb: // map (eight-byte uint64_t for n follow) + { + basic_json result = value_t::object; + const auto len = static_cast(get_from_vector(v, current_idx)); + idx += 8; // skip 8 size bytes + for (size_t i = 0; i < len; ++i) + { + std::string key = from_cbor_internal(v, idx); + result[key] = from_cbor_internal(v, idx); + } + return result; + } + + case 0xbf: // map (indefinite length) + { + basic_json result = value_t::object; + while (v.at(idx) != 0xff) + { + std::string key = from_cbor_internal(v, idx); + result[key] = from_cbor_internal(v, idx); + } + // skip break byte (0xFF) + idx += 1; + return result; + } + + case 0xf4: // false + { + return false; + } + + case 0xf5: // true + { + return true; + } + + case 0xf6: // null + { + return value_t::null; + } + + case 0xf9: // Half-Precision Float (two-byte IEEE 754) + { + idx += 2; // skip two content bytes + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added to + // IEEE 754 in 2008, today's programming platforms often still + // only have limited support for them. It is very easy to + // include at least decoding support for them even without such + // support. An example of a small decoder for half-precision + // floating-point numbers in the C language is shown in Fig. 3. + const int half = (v.at(current_idx + 1) << 8) + v.at(current_idx + 2); + const int exp = (half >> 10) & 0x1f; + const int mant = half & 0x3ff; + double val; + if (exp == 0) + { + val = std::ldexp(mant, -24); + } + else if (exp != 31) + { + val = std::ldexp(mant + 1024, exp - 25); + } + else + { + val = mant == 0 + ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + } + return (half & 0x8000) != 0 ? -val : val; + } + + case 0xfa: // Single-Precision Float (four-byte IEEE 754) + { + // copy bytes in reverse order into the float variable + float res; + for (size_t byte = 0; byte < sizeof(float); ++byte) + { + reinterpret_cast(&res)[sizeof(float) - byte - 1] = v.at(current_idx + 1 + byte); + } + idx += sizeof(float); // skip content bytes + return res; + } + + case 0xfb: // Double-Precision Float (eight-byte IEEE 754) + { + // copy bytes in reverse order into the double variable + double res; + for (size_t byte = 0; byte < sizeof(double); ++byte) + { + reinterpret_cast(&res)[sizeof(double) - byte - 1] = v.at(current_idx + 1 + byte); + } + idx += sizeof(double); // skip content bytes + return res; + } + + default: // anything else (0xFF is handled inside the other types) + { + JSON_THROW(std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast(v[current_idx])))); + } + } + } + + public: + /*! + @brief create a MessagePack serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the MessagePack + serialization format. MessagePack is a binary serialization format which + aims to be more compact than JSON itself, yet more efficient to parse. + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in MessagePack format.,to_msgpack} + + @sa http://msgpack.org + @sa @ref from_msgpack(const std::vector&, const size_t) for the + analogous deserialization + @sa @ref to_cbor(const basic_json& for the related CBOR format + + @since version 2.0.9 + */ + static std::vector to_msgpack(const basic_json& j) + { + std::vector result; + to_msgpack_internal(j, result); + return result; + } + + /*! + @brief create a JSON value from a byte vector in MessagePack format + + Deserializes a given byte vector @a v to a JSON value using the MessagePack + serialization format. + + @param[in] v a byte vector in MessagePack format + @param[in] start_index the index to start reading from @a v (0 by default) + @return deserialized JSON value + + @throw std::invalid_argument if unsupported features from MessagePack were + used in the given vector @a v or if the input is not valid MessagePack + @throw std::out_of_range if the given vector ends prematurely + + @complexity Linear in the size of the byte vector @a v. + + @liveexample{The example shows the deserialization of a byte vector in + MessagePack format to a JSON value.,from_msgpack} + + @sa http://msgpack.org + @sa @ref to_msgpack(const basic_json&) for the analogous serialization + @sa @ref from_cbor(const std::vector&, const size_t) for the + related CBOR format + + @since version 2.0.9, parameter @a start_index since 2.1.1 + */ + static basic_json from_msgpack(const std::vector& v, + const size_t start_index = 0) + { + size_t i = start_index; + return from_msgpack_internal(v, i); + } + + /*! + @brief create a MessagePack serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the CBOR (Concise + Binary Object Representation) serialization format. CBOR is a binary + serialization format which aims to be more compact than JSON itself, yet + more efficient to parse. + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in CBOR format.,to_cbor} + + @sa http://cbor.io + @sa @ref from_cbor(const std::vector&, const size_t) for the + analogous deserialization + @sa @ref to_msgpack(const basic_json& for the related MessagePack format + + @since version 2.0.9 + */ + static std::vector to_cbor(const basic_json& j) + { + std::vector result; + to_cbor_internal(j, result); + return result; + } + + /*! + @brief create a JSON value from a byte vector in CBOR format + + Deserializes a given byte vector @a v to a JSON value using the CBOR + (Concise Binary Object Representation) serialization format. + + @param[in] v a byte vector in CBOR format + @param[in] start_index the index to start reading from @a v (0 by default) + @return deserialized JSON value + + @throw std::invalid_argument if unsupported features from CBOR were used in + the given vector @a v or if the input is not valid MessagePack + @throw std::out_of_range if the given vector ends prematurely + + @complexity Linear in the size of the byte vector @a v. + + @liveexample{The example shows the deserialization of a byte vector in CBOR + format to a JSON value.,from_cbor} + + @sa http://cbor.io + @sa @ref to_cbor(const basic_json&) for the analogous serialization + @sa @ref from_msgpack(const std::vector&, const size_t) for the + related MessagePack format + + @since version 2.0.9, parameter @a start_index since 2.1.1 + */ + static basic_json from_cbor(const std::vector& v, + const size_t start_index = 0) + { + size_t i = start_index; + return from_cbor_internal(v, i); + } + + /// @} + + /////////////////////////// + // convenience functions // + /////////////////////////// + + /*! + @brief return the type as string + + Returns the type name as string to be used in error messages - usually to + indicate that a function was called on a wrong JSON type. + + @return basically a string representation of a the @a m_type member + + @complexity Constant. + + @liveexample{The following code exemplifies `type_name()` for all JSON + types.,type_name} + + @since version 1.0.0, public since 2.1.0 + */ + std::string type_name() const + { + { + switch (m_type) + { + case value_t::null: + return "null"; + case value_t::object: + return "object"; + case value_t::array: + return "array"; + case value_t::string: + return "string"; + case value_t::boolean: + return "boolean"; + case value_t::discarded: + return "discarded"; + default: + return "number"; + } + } + } + + private: + /*! + @brief calculates the extra space to escape a JSON string + + @param[in] s the string to escape + @return the number of characters required to escape string @a s + + @complexity Linear in the length of string @a s. + */ + static std::size_t extra_space(const string_t& s) noexcept + { + return std::accumulate(s.begin(), s.end(), size_t{}, + [](size_t res, typename string_t::value_type c) + { + switch (c) + { + case '"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + { + // from c (1 byte) to \x (2 bytes) + return res + 1; + } + + default: + { + if (c >= 0x00 and c <= 0x1f) + { + // from c (1 byte) to \uxxxx (6 bytes) + return res + 5; + } + + return res; + } + } + }); + } + + /*! + @brief escape a string + + Escape a string by replacing certain special characters by a sequence of + an escape character (backslash) and another character and other control + characters by a sequence of "\u" followed by a four-digit hex + representation. + + @param[in] s the string to escape + @return the escaped string + + @complexity Linear in the length of string @a s. + */ + static string_t escape_string(const string_t& s) + { + const auto space = extra_space(s); + if (space == 0) + { + return s; + } + + // create a result string of necessary size + string_t result(s.size() + space, '\\'); + std::size_t pos = 0; + + for (const auto& c : s) + { + switch (c) + { + // quotation mark (0x22) + case '"': + { + result[pos + 1] = '"'; + pos += 2; + break; + } + + // reverse solidus (0x5c) + case '\\': + { + // nothing to change + pos += 2; + break; + } + + // backspace (0x08) + case '\b': + { + result[pos + 1] = 'b'; + pos += 2; + break; + } + + // formfeed (0x0c) + case '\f': + { + result[pos + 1] = 'f'; + pos += 2; + break; + } + + // newline (0x0a) + case '\n': + { + result[pos + 1] = 'n'; + pos += 2; + break; + } + + // carriage return (0x0d) + case '\r': + { + result[pos + 1] = 'r'; + pos += 2; + break; + } + + // horizontal tab (0x09) + case '\t': + { + result[pos + 1] = 't'; + pos += 2; + break; + } + + default: + { + if (c >= 0x00 and c <= 0x1f) + { + // convert a number 0..15 to its hex representation + // (0..f) + static const char hexify[16] = + { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + // print character c as \uxxxx + for (const char m : + { 'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f] + }) + { + result[++pos] = m; + } + + ++pos; + } + else + { + // all other characters are added as-is + result[pos++] = c; + } + break; + } + } + } + + return result; + } + + + /*! + @brief locale-independent serialization for built-in arithmetic types + */ + struct numtostr + { + public: + template + numtostr(NumberType value) + { + x_write(value, std::is_integral()); + } + + const char* c_str() const + { + return m_buf.data(); + } + + private: + /// a (hopefully) large enough character buffer + std::array < char, 64 > m_buf{{}}; + + template + void x_write(NumberType x, /*is_integral=*/std::true_type) + { + // special case for "0" + if (x == 0) + { + m_buf[0] = '0'; + return; + } + + const bool is_negative = x < 0; + size_t i = 0; + + // spare 1 byte for '\0' + while (x != 0 and i < m_buf.size() - 1) + { + const auto digit = std::labs(static_cast(x % 10)); + m_buf[i++] = static_cast('0' + digit); + x /= 10; + } + + // make sure the number has been processed completely + assert(x == 0); + + if (is_negative) + { + // make sure there is capacity for the '-' + assert(i < m_buf.size() - 2); + m_buf[i++] = '-'; + } + + std::reverse(m_buf.begin(), m_buf.begin() + i); + } + + template + void x_write(NumberType x, /*is_integral=*/std::false_type) + { + // special case for 0.0 and -0.0 + if (x == 0) + { + size_t i = 0; + if (std::signbit(x)) + { + m_buf[i++] = '-'; + } + m_buf[i++] = '0'; + m_buf[i++] = '.'; + m_buf[i] = '0'; + return; + } + + // get number of digits for a text -> float -> text round-trip + static constexpr auto d = std::numeric_limits::digits10; + + // the actual conversion + const auto written_bytes = snprintf(m_buf.data(), m_buf.size(), "%.*g", d, x); + + // negative value indicates an error + assert(written_bytes > 0); + // check if buffer was large enough + assert(static_cast(written_bytes) < m_buf.size()); + + // read information from locale + const auto loc = localeconv(); + assert(loc != nullptr); + const char thousands_sep = !loc->thousands_sep ? '\0' + : loc->thousands_sep[0]; + + const char decimal_point = !loc->decimal_point ? '\0' + : loc->decimal_point[0]; + + // erase thousands separator + if (thousands_sep != '\0') + { + const auto end = std::remove(m_buf.begin(), m_buf.begin() + written_bytes, thousands_sep); + std::fill(end, m_buf.end(), '\0'); + } + + // convert decimal point to '.' + if (decimal_point != '\0' and decimal_point != '.') + { + for (auto& c : m_buf) + { + if (c == decimal_point) + { + c = '.'; + break; + } + } + } + + // determine if need to append ".0" + size_t i = 0; + bool value_is_int_like = true; + for (i = 0; i < m_buf.size(); ++i) + { + // break when end of number is reached + if (m_buf[i] == '\0') + { + break; + } + + // check if we find non-int character + value_is_int_like = value_is_int_like and m_buf[i] != '.' and + m_buf[i] != 'e' and m_buf[i] != 'E'; + } + + if (value_is_int_like) + { + // there must be 2 bytes left for ".0" + assert((i + 2) < m_buf.size()); + // we write to the end of the number + assert(m_buf[i] == '\0'); + assert(m_buf[i - 1] != '\0'); + + // add ".0" + m_buf[i] = '.'; + m_buf[i + 1] = '0'; + + // the resulting string is properly terminated + assert(m_buf[i + 2] == '\0'); + } + } + }; + + + /*! + @brief internal implementation of the serialization function + + This function is called by the public member function dump and organizes + the serialization internally. The indentation level is propagated as + additional parameter. In case of arrays and objects, the function is + called recursively. Note that + + - strings and object keys are escaped using `escape_string()` + - integer numbers are converted implicitly via `operator<<` + - floating-point numbers are converted to a string using `"%g"` format + + @param[out] o stream to write to + @param[in] pretty_print whether the output shall be pretty-printed + @param[in] indent_step the indent level + @param[in] current_indent the current indent level (only used internally) + */ + void dump(std::ostream& o, + const bool pretty_print, + const unsigned int indent_step, + const unsigned int current_indent = 0) const + { + // variable to hold indentation for recursive calls + unsigned int new_indent = current_indent; + + switch (m_type) + { + case value_t::object: + { + if (m_value.object->empty()) + { + o << "{}"; + return; + } + + o << "{"; + + // increase indentation + if (pretty_print) + { + new_indent += indent_step; + o << "\n"; + } + + for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i) + { + if (i != m_value.object->cbegin()) + { + o << (pretty_print ? ",\n" : ","); + } + o << string_t(new_indent, ' ') << "\"" + << escape_string(i->first) << "\":" + << (pretty_print ? " " : ""); + i->second.dump(o, pretty_print, indent_step, new_indent); + } + + // decrease indentation + if (pretty_print) + { + new_indent -= indent_step; + o << "\n"; + } + + o << string_t(new_indent, ' ') + "}"; + return; + } + + case value_t::array: + { + if (m_value.array->empty()) + { + o << "[]"; + return; + } + + o << "["; + + // increase indentation + if (pretty_print) + { + new_indent += indent_step; + o << "\n"; + } + + for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i) + { + if (i != m_value.array->cbegin()) + { + o << (pretty_print ? ",\n" : ","); + } + o << string_t(new_indent, ' '); + i->dump(o, pretty_print, indent_step, new_indent); + } + + // decrease indentation + if (pretty_print) + { + new_indent -= indent_step; + o << "\n"; + } + + o << string_t(new_indent, ' ') << "]"; + return; + } + + case value_t::string: + { + o << string_t("\"") << escape_string(*m_value.string) << "\""; + return; + } + + case value_t::boolean: + { + o << (m_value.boolean ? "true" : "false"); + return; + } + + case value_t::number_integer: + { + o << numtostr(m_value.number_integer).c_str(); + return; + } + + case value_t::number_unsigned: + { + o << numtostr(m_value.number_unsigned).c_str(); + return; + } + + case value_t::number_float: + { + o << numtostr(m_value.number_float).c_str(); + return; + } + + case value_t::discarded: + { + o << ""; + return; + } + + case value_t::null: + { + o << "null"; + return; + } + } + } + + private: + ////////////////////// + // member variables // + ////////////////////// + + /// the type of the current element + value_t m_type = value_t::null; + + /// the value of the current element + json_value m_value = {}; + + + private: + /////////////// + // iterators // + /////////////// + + /*! + @brief an iterator for primitive JSON types + + This class models an iterator for primitive JSON types (boolean, number, + string). It's only purpose is to allow the iterator/const_iterator classes + to "iterate" over primitive values. Internally, the iterator is modeled by + a `difference_type` variable. Value begin_value (`0`) models the begin, + end_value (`1`) models past the end. + */ + class primitive_iterator_t + { + public: + + difference_type get_value() const noexcept + { + return m_it; + } + /// set iterator to a defined beginning + void set_begin() noexcept + { + m_it = begin_value; + } + + /// set iterator to a defined past the end + void set_end() noexcept + { + m_it = end_value; + } + + /// return whether the iterator can be dereferenced + constexpr bool is_begin() const noexcept + { + return (m_it == begin_value); + } + + /// return whether the iterator is at end + constexpr bool is_end() const noexcept + { + return (m_it == end_value); + } + + friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it == rhs.m_it; + } + + friend constexpr bool operator!=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return !(lhs == rhs); + } + + friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it < rhs.m_it; + } + + friend constexpr bool operator<=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it <= rhs.m_it; + } + + friend constexpr bool operator>(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it > rhs.m_it; + } + + friend constexpr bool operator>=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it >= rhs.m_it; + } + + primitive_iterator_t operator+(difference_type i) + { + auto result = *this; + result += i; + return result; + } + + friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it - rhs.m_it; + } + + friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it) + { + return os << it.m_it; + } + + primitive_iterator_t& operator++() + { + ++m_it; + return *this; + } + + primitive_iterator_t operator++(int) + { + auto result = *this; + m_it++; + return result; + } + + primitive_iterator_t& operator--() + { + --m_it; + return *this; + } + + primitive_iterator_t operator--(int) + { + auto result = *this; + m_it--; + return result; + } + + primitive_iterator_t& operator+=(difference_type n) + { + m_it += n; + return *this; + } + + primitive_iterator_t& operator-=(difference_type n) + { + m_it -= n; + return *this; + } + + private: + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + /// iterator as signed integer type + difference_type m_it = std::numeric_limits::denorm_min(); + }; + + /*! + @brief an iterator value + + @note This structure could easily be a union, but MSVC currently does not + allow unions members with complex constructors, see + https://github.com/nlohmann/json/pull/105. + */ + struct internal_iterator + { + /// iterator for JSON objects + typename object_t::iterator object_iterator; + /// iterator for JSON arrays + typename array_t::iterator array_iterator; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator; + + /// create an uninitialized internal_iterator + internal_iterator() noexcept + : object_iterator(), array_iterator(), primitive_iterator() + {} + }; + + /// proxy class for the iterator_wrapper functions + template + class iteration_proxy + { + private: + /// helper class for iteration + class iteration_proxy_internal + { + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + size_t array_index = 0; + + public: + explicit iteration_proxy_internal(IteratorType it) noexcept + : anchor(it) + {} + + /// dereference operator (needed for range-based for) + iteration_proxy_internal& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_internal& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// inequality operator (needed for range-based for) + bool operator!= (const iteration_proxy_internal& o) const + { + return anchor != o.anchor; + } + + /// return key of the iterator + typename basic_json::string_t key() const + { + assert(anchor.m_object != nullptr); + + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + { + return std::to_string(array_index); + } + + // use key from the object + case value_t::object: + { + return anchor.key(); + } + + // use an empty key for all primitive types + default: + { + return ""; + } + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } + }; + + /// the container to iterate + typename IteratorType::reference container; + + public: + /// construct iteration proxy from a container + explicit iteration_proxy(typename IteratorType::reference cont) + : container(cont) + {} + + /// return iterator begin (needed for range-based for) + iteration_proxy_internal begin() noexcept + { + return iteration_proxy_internal(container.begin()); + } + + /// return iterator end (needed for range-based for) + iteration_proxy_internal end() noexcept + { + return iteration_proxy_internal(container.end()); + } + }; + + public: + /*! + @brief a template for a random access iterator for the @ref basic_json class + + This class implements a both iterators (iterator and const_iterator) for the + @ref basic_json class. + + @note An iterator is called *initialized* when a pointer to a JSON value + has been set (e.g., by a constructor or a copy assignment). If the + iterator is default-constructed, it is *uninitialized* and most + methods are undefined. **The library uses assertions to detect calls + on uninitialized iterators.** + + @requirement The class satisfies the following concept requirements: + - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): + The iterator that can be moved to point (forward and backward) to any + element in constant time. + + @since version 1.0.0, simplified in version 2.0.9 + */ + template + class iter_impl : public std::iterator + { + /// allow basic_json to access private members + friend class basic_json; + + // make sure U is basic_json or const basic_json + static_assert(std::is_same::value + or std::is_same::value, + "iter_impl only accepts (const) basic_json"); + + public: + /// the type of the values when the iterator is dereferenced + using value_type = typename basic_json::value_type; + /// a type to represent differences between iterators + using difference_type = typename basic_json::difference_type; + /// defines a pointer to the type iterated over (value_type) + using pointer = typename std::conditional::value, + typename basic_json::const_pointer, + typename basic_json::pointer>::type; + /// defines a reference to the type iterated over (value_type) + using reference = typename std::conditional::value, + typename basic_json::const_reference, + typename basic_json::reference>::type; + /// the category of the iterator + using iterator_category = std::bidirectional_iterator_tag; + + /// default constructor + iter_impl() = default; + + /*! + @brief constructor for a given JSON instance + @param[in] object pointer to a JSON object for this iterator + @pre object != nullptr + @post The iterator is initialized; i.e. `m_object != nullptr`. + */ + explicit iter_impl(pointer object) noexcept + : m_object(object) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + m_it.object_iterator = typename object_t::iterator(); + break; + } + + case basic_json::value_t::array: + { + m_it.array_iterator = typename array_t::iterator(); + break; + } + + default: + { + m_it.primitive_iterator = primitive_iterator_t(); + break; + } + } + } + + /* + Use operator `const_iterator` instead of `const_iterator(const iterator& + other) noexcept` to avoid two class definitions for @ref iterator and + @ref const_iterator. + + This function is only called if this class is an @ref iterator. If this + class is a @ref const_iterator this function is not called. + */ + operator const_iterator() const + { + const_iterator ret; + + if (m_object) + { + ret.m_object = m_object; + ret.m_it = m_it; + } + + return ret; + } + + /*! + @brief copy constructor + @param[in] other iterator to copy from + @note It is not checked whether @a other is initialized. + */ + iter_impl(const iter_impl& other) noexcept + : m_object(other.m_object), m_it(other.m_it) + {} + + /*! + @brief copy assignment + @param[in,out] other iterator to copy from + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(iter_impl other) noexcept( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + std::swap(m_object, other.m_object); + std::swap(m_it, other.m_it); + return *this; + } + + private: + /*! + @brief set the iterator to the first value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_begin() noexcept + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + m_it.object_iterator = m_object->m_value.object->begin(); + break; + } + + case basic_json::value_t::array: + { + m_it.array_iterator = m_object->m_value.array->begin(); + break; + } + + case basic_json::value_t::null: + { + // set to end so begin()==end() is true: null is empty + m_it.primitive_iterator.set_end(); + break; + } + + default: + { + m_it.primitive_iterator.set_begin(); + break; + } + } + } + + /*! + @brief set the iterator past the last value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_end() noexcept + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + m_it.object_iterator = m_object->m_value.object->end(); + break; + } + + case basic_json::value_t::array: + { + m_it.array_iterator = m_object->m_value.array->end(); + break; + } + + default: + { + m_it.primitive_iterator.set_end(); + break; + } + } + } + + public: + /*! + @brief return a reference to the value pointed to by the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator*() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + assert(m_it.object_iterator != m_object->m_value.object->end()); + return m_it.object_iterator->second; + } + + case basic_json::value_t::array: + { + assert(m_it.array_iterator != m_object->m_value.array->end()); + return *m_it.array_iterator; + } + + case basic_json::value_t::null: + { + JSON_THROW(std::out_of_range("cannot get value")); + } + + default: + { + if (m_it.primitive_iterator.is_begin()) + { + return *m_object; + } + + JSON_THROW(std::out_of_range("cannot get value")); + } + } + } + + /*! + @brief dereference the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + pointer operator->() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + assert(m_it.object_iterator != m_object->m_value.object->end()); + return &(m_it.object_iterator->second); + } + + case basic_json::value_t::array: + { + assert(m_it.array_iterator != m_object->m_value.array->end()); + return &*m_it.array_iterator; + } + + default: + { + if (m_it.primitive_iterator.is_begin()) + { + return m_object; + } + + JSON_THROW(std::out_of_range("cannot get value")); + } + } + } + + /*! + @brief post-increment (it++) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator++(int) + { + auto result = *this; + ++(*this); + return result; + } + + /*! + @brief pre-increment (++it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator++() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + std::advance(m_it.object_iterator, 1); + break; + } + + case basic_json::value_t::array: + { + std::advance(m_it.array_iterator, 1); + break; + } + + default: + { + ++m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief post-decrement (it--) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator--(int) + { + auto result = *this; + --(*this); + return result; + } + + /*! + @brief pre-decrement (--it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator--() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + std::advance(m_it.object_iterator, -1); + break; + } + + case basic_json::value_t::array: + { + std::advance(m_it.array_iterator, -1); + break; + } + + default: + { + --m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief comparison: equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator==(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (m_object != other.m_object) + { + JSON_THROW(std::domain_error("cannot compare iterators of different containers")); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + return (m_it.object_iterator == other.m_it.object_iterator); + } + + case basic_json::value_t::array: + { + return (m_it.array_iterator == other.m_it.array_iterator); + } + + default: + { + return (m_it.primitive_iterator == other.m_it.primitive_iterator); + } + } + } + + /*! + @brief comparison: not equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator!=(const iter_impl& other) const + { + return not operator==(other); + } + + /*! + @brief comparison: smaller + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (m_object != other.m_object) + { + JSON_THROW(std::domain_error("cannot compare iterators of different containers")); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + JSON_THROW(std::domain_error("cannot compare order of object iterators")); + } + + case basic_json::value_t::array: + { + return (m_it.array_iterator < other.m_it.array_iterator); + } + + default: + { + return (m_it.primitive_iterator < other.m_it.primitive_iterator); + } + } + } + + /*! + @brief comparison: less than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<=(const iter_impl& other) const + { + return not other.operator < (*this); + } + + /*! + @brief comparison: greater than + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>(const iter_impl& other) const + { + return not operator<=(other); + } + + /*! + @brief comparison: greater than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>=(const iter_impl& other) const + { + return not operator<(other); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator+=(difference_type i) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + JSON_THROW(std::domain_error("cannot use offsets with object iterators")); + } + + case basic_json::value_t::array: + { + std::advance(m_it.array_iterator, i); + break; + } + + default: + { + m_it.primitive_iterator += i; + break; + } + } + + return *this; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator-=(difference_type i) + { + return operator+=(-i); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator+(difference_type i) + { + auto result = *this; + result += i; + return result; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator-(difference_type i) + { + auto result = *this; + result -= i; + return result; + } + + /*! + @brief return difference + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + difference_type operator-(const iter_impl& other) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + JSON_THROW(std::domain_error("cannot use offsets with object iterators")); + } + + case basic_json::value_t::array: + { + return m_it.array_iterator - other.m_it.array_iterator; + } + + default: + { + return m_it.primitive_iterator - other.m_it.primitive_iterator; + } + } + } + + /*! + @brief access to successor + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator[](difference_type n) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + JSON_THROW(std::domain_error("cannot use operator[] for object iterators")); + } + + case basic_json::value_t::array: + { + return *std::next(m_it.array_iterator, n); + } + + case basic_json::value_t::null: + { + JSON_THROW(std::out_of_range("cannot get value")); + } + + default: + { + if (m_it.primitive_iterator.get_value() == -n) + { + return *m_object; + } + + JSON_THROW(std::out_of_range("cannot get value")); + } + } + } + + /*! + @brief return the key of an object iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + typename object_t::key_type key() const + { + assert(m_object != nullptr); + + if (m_object->is_object()) + { + return m_it.object_iterator->first; + } + + JSON_THROW(std::domain_error("cannot use key() for non-object iterators")); + } + + /*! + @brief return the value of an iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference value() const + { + return operator*(); + } + + private: + /// associated JSON instance + pointer m_object = nullptr; + /// the actual iterator of the associated instance + internal_iterator m_it = internal_iterator(); + }; + + /*! + @brief a template for a reverse iterator class + + @tparam Base the base iterator type to reverse. Valid types are @ref + iterator (to create @ref reverse_iterator) and @ref const_iterator (to + create @ref const_reverse_iterator). + + @requirement The class satisfies the following concept requirements: + - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): + The iterator that can be moved to point (forward and backward) to any + element in constant time. + - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + + @since version 1.0.0 + */ + template + class json_reverse_iterator : public std::reverse_iterator + { + public: + /// shortcut to the reverse iterator adaptor + using base_iterator = std::reverse_iterator; + /// the reference type for the pointed-to element + using reference = typename Base::reference; + + /// create reverse iterator from iterator + json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept + : base_iterator(it) + {} + + /// create reverse iterator from base class + json_reverse_iterator(const base_iterator& it) noexcept + : base_iterator(it) + {} + + /// post-increment (it++) + json_reverse_iterator operator++(int) + { + return base_iterator::operator++(1); + } + + /// pre-increment (++it) + json_reverse_iterator& operator++() + { + base_iterator::operator++(); + return *this; + } + + /// post-decrement (it--) + json_reverse_iterator operator--(int) + { + return base_iterator::operator--(1); + } + + /// pre-decrement (--it) + json_reverse_iterator& operator--() + { + base_iterator::operator--(); + return *this; + } + + /// add to iterator + json_reverse_iterator& operator+=(difference_type i) + { + base_iterator::operator+=(i); + return *this; + } + + /// add to iterator + json_reverse_iterator operator+(difference_type i) const + { + auto result = *this; + result += i; + return result; + } + + /// subtract from iterator + json_reverse_iterator operator-(difference_type i) const + { + auto result = *this; + result -= i; + return result; + } + + /// return difference + difference_type operator-(const json_reverse_iterator& other) const + { + return this->base() - other.base(); + } + + /// access to successor + reference operator[](difference_type n) const + { + return *(this->operator+(n)); + } + + /// return the key of an object iterator + typename object_t::key_type key() const + { + auto it = --this->base(); + return it.key(); + } + + /// return the value of an iterator + reference value() const + { + auto it = --this->base(); + return it.operator * (); + } + }; + + + private: + ////////////////////// + // lexer and parser // + ////////////////////// + + /*! + @brief lexical analysis + + This class organizes the lexical analysis during JSON deserialization. The + core of it is a scanner generated by [re2c](http://re2c.org) that + processes a buffer and recognizes tokens according to RFC 7159. + */ + class lexer + { + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the `true` literal + literal_false, ///< the `false` literal + literal_null, ///< the `null` literal + value_string, ///< a string -- use get_string() for actual value + value_unsigned, ///< an unsigned integer -- use get_number() for actual value + value_integer, ///< a signed integer -- use get_number() for actual value + value_float, ///< an floating point number -- use get_number() for actual value + begin_array, ///< the character for array begin `[` + begin_object, ///< the character for object begin `{` + end_array, ///< the character for array end `]` + end_object, ///< the character for object end `}` + name_separator, ///< the name separator `:` + value_separator, ///< the value separator `,` + parse_error, ///< indicating a parse error + end_of_input ///< indicating the end of the input buffer + }; + + /// the char type to use in the lexer + using lexer_char_t = unsigned char; + + /// a lexer from a buffer with given length + lexer(const lexer_char_t* buff, const size_t len) noexcept + : m_content(buff) + { + assert(m_content != nullptr); + m_start = m_cursor = m_content; + m_limit = m_content + len; + } + + /// a lexer from an input stream + explicit lexer(std::istream& s) + : m_stream(&s), m_line_buffer() + { + // immediately abort if stream is erroneous + if (s.fail()) + { + JSON_THROW(std::invalid_argument("stream error")); + } + + // fill buffer + fill_line_buffer(); + + // skip UTF-8 byte-order mark + if (m_line_buffer.size() >= 3 and m_line_buffer.substr(0, 3) == "\xEF\xBB\xBF") + { + m_line_buffer[0] = ' '; + m_line_buffer[1] = ' '; + m_line_buffer[2] = ' '; + } + } + + // switch off unwanted functions (due to pointer members) + lexer() = delete; + lexer(const lexer&) = delete; + lexer operator=(const lexer&) = delete; + + /*! + @brief create a string from one or two Unicode code points + + There are two cases: (1) @a codepoint1 is in the Basic Multilingual + Plane (U+0000 through U+FFFF) and @a codepoint2 is 0, or (2) + @a codepoint1 and @a codepoint2 are a UTF-16 surrogate pair to + represent a code point above U+FFFF. + + @param[in] codepoint1 the code point (can be high surrogate) + @param[in] codepoint2 the code point (can be low surrogate or 0) + + @return string representation of the code point; the length of the + result string is between 1 and 4 characters. + + @throw std::out_of_range if code point is > 0x10ffff; example: `"code + points above 0x10FFFF are invalid"` + @throw std::invalid_argument if the low surrogate is invalid; example: + `""missing or wrong low surrogate""` + + @complexity Constant. + + @see + */ + static string_t to_unicode(const std::size_t codepoint1, + const std::size_t codepoint2 = 0) + { + // calculate the code point from the given code points + std::size_t codepoint = codepoint1; + + // check if codepoint1 is a high surrogate + if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF) + { + // check if codepoint2 is a low surrogate + if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF) + { + codepoint = + // high surrogate occupies the most significant 22 bits + (codepoint1 << 10) + // low surrogate occupies the least significant 15 bits + + codepoint2 + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00; + } + else + { + JSON_THROW(std::invalid_argument("missing or wrong low surrogate")); + } + } + + string_t result; + + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + result.append(1, static_cast(codepoint)); + } + else if (codepoint <= 0x7ff) + { + // 2-byte characters: 110xxxxx 10xxxxxx + result.append(1, static_cast(0xC0 | ((codepoint >> 6) & 0x1F))); + result.append(1, static_cast(0x80 | (codepoint & 0x3F))); + } + else if (codepoint <= 0xffff) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + result.append(1, static_cast(0xE0 | ((codepoint >> 12) & 0x0F))); + result.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + result.append(1, static_cast(0x80 | (codepoint & 0x3F))); + } + else if (codepoint <= 0x10ffff) + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + result.append(1, static_cast(0xF0 | ((codepoint >> 18) & 0x07))); + result.append(1, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + result.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + result.append(1, static_cast(0x80 | (codepoint & 0x3F))); + } + else + { + JSON_THROW(std::out_of_range("code points above 0x10FFFF are invalid")); + } + + return result; + } + + /// return name of values of type token_type (only used for errors) + static std::string token_type_name(const token_type t) + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case lexer::token_type::value_unsigned: + case lexer::token_type::value_integer: + case lexer::token_type::value_float: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + default: + { + // catch non-enum values + return "unknown token"; // LCOV_EXCL_LINE + } + } + } + + /*! + This function implements a scanner for JSON. It is specified using + regular expressions that try to follow RFC 7159 as close as possible. + These regular expressions are then translated into a minimized + deterministic finite automaton (DFA) by the tool + [re2c](http://re2c.org). As a result, the translated code for this + function consists of a large block of code with `goto` jumps. + + @return the class of the next token read from the buffer + + @complexity Linear in the length of the input.\n + + Proposition: The loop below will always terminate for finite input.\n + + Proof (by contradiction): Assume a finite input. To loop forever, the + loop must never hit code with a `break` statement. The only code + snippets without a `break` statement are the continue statements for + whitespace and byte-order-marks. To loop forever, the input must be an + infinite sequence of whitespace or byte-order-marks. This contradicts + the assumption of finite input, q.e.d. + */ + token_type scan() + { + while (true) + { + // pointer for backtracking information + m_marker = nullptr; + + // remember the begin of the token + m_start = m_cursor; + assert(m_start != nullptr); + + + { + lexer_char_t yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 32, 0, 0, 32, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 160, 128, 0, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 0, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + if ((m_limit - m_cursor) < 5) + { + fill_line_buffer(5); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yybm[0 + yych] & 32) + { + goto basic_json_parser_6; + } + if (yych <= '[') + { + if (yych <= '-') + { + if (yych <= '"') + { + if (yych <= 0x00) + { + goto basic_json_parser_2; + } + if (yych <= '!') + { + goto basic_json_parser_4; + } + goto basic_json_parser_9; + } + else + { + if (yych <= '+') + { + goto basic_json_parser_4; + } + if (yych <= ',') + { + goto basic_json_parser_10; + } + goto basic_json_parser_12; + } + } + else + { + if (yych <= '9') + { + if (yych <= '/') + { + goto basic_json_parser_4; + } + if (yych <= '0') + { + goto basic_json_parser_13; + } + goto basic_json_parser_15; + } + else + { + if (yych <= ':') + { + goto basic_json_parser_17; + } + if (yych <= 'Z') + { + goto basic_json_parser_4; + } + goto basic_json_parser_19; + } + } + } + else + { + if (yych <= 'n') + { + if (yych <= 'e') + { + if (yych == ']') + { + goto basic_json_parser_21; + } + goto basic_json_parser_4; + } + else + { + if (yych <= 'f') + { + goto basic_json_parser_23; + } + if (yych <= 'm') + { + goto basic_json_parser_4; + } + goto basic_json_parser_24; + } + } + else + { + if (yych <= 'z') + { + if (yych == 't') + { + goto basic_json_parser_25; + } + goto basic_json_parser_4; + } + else + { + if (yych <= '{') + { + goto basic_json_parser_26; + } + if (yych == '}') + { + goto basic_json_parser_28; + } + goto basic_json_parser_4; + } + } + } +basic_json_parser_2: + ++m_cursor; + { + last_token_type = token_type::end_of_input; + break; + } +basic_json_parser_4: + ++m_cursor; +basic_json_parser_5: + { + last_token_type = token_type::parse_error; + break; + } +basic_json_parser_6: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yybm[0 + yych] & 32) + { + goto basic_json_parser_6; + } + { + continue; + } +basic_json_parser_9: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych <= 0x1F) + { + goto basic_json_parser_5; + } + if (yych <= 0x7F) + { + goto basic_json_parser_31; + } + if (yych <= 0xC1) + { + goto basic_json_parser_5; + } + if (yych <= 0xF4) + { + goto basic_json_parser_31; + } + goto basic_json_parser_5; +basic_json_parser_10: + ++m_cursor; + { + last_token_type = token_type::value_separator; + break; + } +basic_json_parser_12: + yych = *++m_cursor; + if (yych <= '/') + { + goto basic_json_parser_5; + } + if (yych <= '0') + { + goto basic_json_parser_43; + } + if (yych <= '9') + { + goto basic_json_parser_45; + } + goto basic_json_parser_5; +basic_json_parser_13: + yyaccept = 1; + yych = *(m_marker = ++m_cursor); + if (yych <= '9') + { + if (yych == '.') + { + goto basic_json_parser_47; + } + if (yych >= '0') + { + goto basic_json_parser_48; + } + } + else + { + if (yych <= 'E') + { + if (yych >= 'E') + { + goto basic_json_parser_51; + } + } + else + { + if (yych == 'e') + { + goto basic_json_parser_51; + } + } + } +basic_json_parser_14: + { + last_token_type = token_type::value_unsigned; + break; + } +basic_json_parser_15: + yyaccept = 1; + m_marker = ++m_cursor; + if ((m_limit - m_cursor) < 3) + { + fill_line_buffer(3); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yybm[0 + yych] & 64) + { + goto basic_json_parser_15; + } + if (yych <= 'D') + { + if (yych == '.') + { + goto basic_json_parser_47; + } + goto basic_json_parser_14; + } + else + { + if (yych <= 'E') + { + goto basic_json_parser_51; + } + if (yych == 'e') + { + goto basic_json_parser_51; + } + goto basic_json_parser_14; + } +basic_json_parser_17: + ++m_cursor; + { + last_token_type = token_type::name_separator; + break; + } +basic_json_parser_19: + ++m_cursor; + { + last_token_type = token_type::begin_array; + break; + } +basic_json_parser_21: + ++m_cursor; + { + last_token_type = token_type::end_array; + break; + } +basic_json_parser_23: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'a') + { + goto basic_json_parser_52; + } + goto basic_json_parser_5; +basic_json_parser_24: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'u') + { + goto basic_json_parser_53; + } + goto basic_json_parser_5; +basic_json_parser_25: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'r') + { + goto basic_json_parser_54; + } + goto basic_json_parser_5; +basic_json_parser_26: + ++m_cursor; + { + last_token_type = token_type::begin_object; + break; + } +basic_json_parser_28: + ++m_cursor; + { + last_token_type = token_type::end_object; + break; + } +basic_json_parser_30: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; +basic_json_parser_31: + if (yybm[0 + yych] & 128) + { + goto basic_json_parser_30; + } + if (yych <= 0xE0) + { + if (yych <= '\\') + { + if (yych <= 0x1F) + { + goto basic_json_parser_32; + } + if (yych <= '"') + { + goto basic_json_parser_33; + } + goto basic_json_parser_35; + } + else + { + if (yych <= 0xC1) + { + goto basic_json_parser_32; + } + if (yych <= 0xDF) + { + goto basic_json_parser_36; + } + goto basic_json_parser_37; + } + } + else + { + if (yych <= 0xEF) + { + if (yych == 0xED) + { + goto basic_json_parser_39; + } + goto basic_json_parser_38; + } + else + { + if (yych <= 0xF0) + { + goto basic_json_parser_40; + } + if (yych <= 0xF3) + { + goto basic_json_parser_41; + } + if (yych <= 0xF4) + { + goto basic_json_parser_42; + } + } + } +basic_json_parser_32: + m_cursor = m_marker; + if (yyaccept <= 1) + { + if (yyaccept == 0) + { + goto basic_json_parser_5; + } + else + { + goto basic_json_parser_14; + } + } + else + { + if (yyaccept == 2) + { + goto basic_json_parser_44; + } + else + { + goto basic_json_parser_58; + } + } +basic_json_parser_33: + ++m_cursor; + { + last_token_type = token_type::value_string; + break; + } +basic_json_parser_35: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= 'e') + { + if (yych <= '/') + { + if (yych == '"') + { + goto basic_json_parser_30; + } + if (yych <= '.') + { + goto basic_json_parser_32; + } + goto basic_json_parser_30; + } + else + { + if (yych <= '\\') + { + if (yych <= '[') + { + goto basic_json_parser_32; + } + goto basic_json_parser_30; + } + else + { + if (yych == 'b') + { + goto basic_json_parser_30; + } + goto basic_json_parser_32; + } + } + } + else + { + if (yych <= 'q') + { + if (yych <= 'f') + { + goto basic_json_parser_30; + } + if (yych == 'n') + { + goto basic_json_parser_30; + } + goto basic_json_parser_32; + } + else + { + if (yych <= 's') + { + if (yych <= 'r') + { + goto basic_json_parser_30; + } + goto basic_json_parser_32; + } + else + { + if (yych <= 't') + { + goto basic_json_parser_30; + } + if (yych <= 'u') + { + goto basic_json_parser_55; + } + goto basic_json_parser_32; + } + } + } +basic_json_parser_36: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= 0x7F) + { + goto basic_json_parser_32; + } + if (yych <= 0xBF) + { + goto basic_json_parser_30; + } + goto basic_json_parser_32; +basic_json_parser_37: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= 0x9F) + { + goto basic_json_parser_32; + } + if (yych <= 0xBF) + { + goto basic_json_parser_36; + } + goto basic_json_parser_32; +basic_json_parser_38: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= 0x7F) + { + goto basic_json_parser_32; + } + if (yych <= 0xBF) + { + goto basic_json_parser_36; + } + goto basic_json_parser_32; +basic_json_parser_39: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= 0x7F) + { + goto basic_json_parser_32; + } + if (yych <= 0x9F) + { + goto basic_json_parser_36; + } + goto basic_json_parser_32; +basic_json_parser_40: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= 0x8F) + { + goto basic_json_parser_32; + } + if (yych <= 0xBF) + { + goto basic_json_parser_38; + } + goto basic_json_parser_32; +basic_json_parser_41: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= 0x7F) + { + goto basic_json_parser_32; + } + if (yych <= 0xBF) + { + goto basic_json_parser_38; + } + goto basic_json_parser_32; +basic_json_parser_42: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= 0x7F) + { + goto basic_json_parser_32; + } + if (yych <= 0x8F) + { + goto basic_json_parser_38; + } + goto basic_json_parser_32; +basic_json_parser_43: + yyaccept = 2; + yych = *(m_marker = ++m_cursor); + if (yych <= '9') + { + if (yych == '.') + { + goto basic_json_parser_47; + } + if (yych >= '0') + { + goto basic_json_parser_48; + } + } + else + { + if (yych <= 'E') + { + if (yych >= 'E') + { + goto basic_json_parser_51; + } + } + else + { + if (yych == 'e') + { + goto basic_json_parser_51; + } + } + } +basic_json_parser_44: + { + last_token_type = token_type::value_integer; + break; + } +basic_json_parser_45: + yyaccept = 2; + m_marker = ++m_cursor; + if ((m_limit - m_cursor) < 3) + { + fill_line_buffer(3); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= '9') + { + if (yych == '.') + { + goto basic_json_parser_47; + } + if (yych <= '/') + { + goto basic_json_parser_44; + } + goto basic_json_parser_45; + } + else + { + if (yych <= 'E') + { + if (yych <= 'D') + { + goto basic_json_parser_44; + } + goto basic_json_parser_51; + } + else + { + if (yych == 'e') + { + goto basic_json_parser_51; + } + goto basic_json_parser_44; + } + } +basic_json_parser_47: + yych = *++m_cursor; + if (yych <= '/') + { + goto basic_json_parser_32; + } + if (yych <= '9') + { + goto basic_json_parser_56; + } + goto basic_json_parser_32; +basic_json_parser_48: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= '/') + { + goto basic_json_parser_50; + } + if (yych <= '9') + { + goto basic_json_parser_48; + } +basic_json_parser_50: + { + last_token_type = token_type::parse_error; + break; + } +basic_json_parser_51: + yych = *++m_cursor; + if (yych <= ',') + { + if (yych == '+') + { + goto basic_json_parser_59; + } + goto basic_json_parser_32; + } + else + { + if (yych <= '-') + { + goto basic_json_parser_59; + } + if (yych <= '/') + { + goto basic_json_parser_32; + } + if (yych <= '9') + { + goto basic_json_parser_60; + } + goto basic_json_parser_32; + } +basic_json_parser_52: + yych = *++m_cursor; + if (yych == 'l') + { + goto basic_json_parser_62; + } + goto basic_json_parser_32; +basic_json_parser_53: + yych = *++m_cursor; + if (yych == 'l') + { + goto basic_json_parser_63; + } + goto basic_json_parser_32; +basic_json_parser_54: + yych = *++m_cursor; + if (yych == 'u') + { + goto basic_json_parser_64; + } + goto basic_json_parser_32; +basic_json_parser_55: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') + { + goto basic_json_parser_32; + } + if (yych <= '9') + { + goto basic_json_parser_65; + } + goto basic_json_parser_32; + } + else + { + if (yych <= 'F') + { + goto basic_json_parser_65; + } + if (yych <= '`') + { + goto basic_json_parser_32; + } + if (yych <= 'f') + { + goto basic_json_parser_65; + } + goto basic_json_parser_32; + } +basic_json_parser_56: + yyaccept = 3; + m_marker = ++m_cursor; + if ((m_limit - m_cursor) < 3) + { + fill_line_buffer(3); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= 'D') + { + if (yych <= '/') + { + goto basic_json_parser_58; + } + if (yych <= '9') + { + goto basic_json_parser_56; + } + } + else + { + if (yych <= 'E') + { + goto basic_json_parser_51; + } + if (yych == 'e') + { + goto basic_json_parser_51; + } + } +basic_json_parser_58: + { + last_token_type = token_type::value_float; + break; + } +basic_json_parser_59: + yych = *++m_cursor; + if (yych <= '/') + { + goto basic_json_parser_32; + } + if (yych >= ':') + { + goto basic_json_parser_32; + } +basic_json_parser_60: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= '/') + { + goto basic_json_parser_58; + } + if (yych <= '9') + { + goto basic_json_parser_60; + } + goto basic_json_parser_58; +basic_json_parser_62: + yych = *++m_cursor; + if (yych == 's') + { + goto basic_json_parser_66; + } + goto basic_json_parser_32; +basic_json_parser_63: + yych = *++m_cursor; + if (yych == 'l') + { + goto basic_json_parser_67; + } + goto basic_json_parser_32; +basic_json_parser_64: + yych = *++m_cursor; + if (yych == 'e') + { + goto basic_json_parser_69; + } + goto basic_json_parser_32; +basic_json_parser_65: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') + { + goto basic_json_parser_32; + } + if (yych <= '9') + { + goto basic_json_parser_71; + } + goto basic_json_parser_32; + } + else + { + if (yych <= 'F') + { + goto basic_json_parser_71; + } + if (yych <= '`') + { + goto basic_json_parser_32; + } + if (yych <= 'f') + { + goto basic_json_parser_71; + } + goto basic_json_parser_32; + } +basic_json_parser_66: + yych = *++m_cursor; + if (yych == 'e') + { + goto basic_json_parser_72; + } + goto basic_json_parser_32; +basic_json_parser_67: + ++m_cursor; + { + last_token_type = token_type::literal_null; + break; + } +basic_json_parser_69: + ++m_cursor; + { + last_token_type = token_type::literal_true; + break; + } +basic_json_parser_71: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') + { + goto basic_json_parser_32; + } + if (yych <= '9') + { + goto basic_json_parser_74; + } + goto basic_json_parser_32; + } + else + { + if (yych <= 'F') + { + goto basic_json_parser_74; + } + if (yych <= '`') + { + goto basic_json_parser_32; + } + if (yych <= 'f') + { + goto basic_json_parser_74; + } + goto basic_json_parser_32; + } +basic_json_parser_72: + ++m_cursor; + { + last_token_type = token_type::literal_false; + break; + } +basic_json_parser_74: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') + { + goto basic_json_parser_32; + } + if (yych <= '9') + { + goto basic_json_parser_30; + } + goto basic_json_parser_32; + } + else + { + if (yych <= 'F') + { + goto basic_json_parser_30; + } + if (yych <= '`') + { + goto basic_json_parser_32; + } + if (yych <= 'f') + { + goto basic_json_parser_30; + } + goto basic_json_parser_32; + } + } + + } + + return last_token_type; + } + + /*! + @brief append data from the stream to the line buffer + + This function is called by the scan() function when the end of the + buffer (`m_limit`) is reached and the `m_cursor` pointer cannot be + incremented without leaving the limits of the line buffer. Note re2c + decides when to call this function. + + If the lexer reads from contiguous storage, there is no trailing null + byte. Therefore, this function must make sure to add these padding + null bytes. + + If the lexer reads from an input stream, this function reads the next + line of the input. + + @pre + p p p p p p u u u u u x . . . . . . + ^ ^ ^ ^ + m_content m_start | m_limit + m_cursor + + @post + u u u u u x x x x x x x . . . . . . + ^ ^ ^ + | m_cursor m_limit + m_start + m_content + */ + void fill_line_buffer(size_t n = 0) + { + // if line buffer is used, m_content points to its data + assert(m_line_buffer.empty() + or m_content == reinterpret_cast(m_line_buffer.data())); + + // if line buffer is used, m_limit is set past the end of its data + assert(m_line_buffer.empty() + or m_limit == m_content + m_line_buffer.size()); + + // pointer relationships + assert(m_content <= m_start); + assert(m_start <= m_cursor); + assert(m_cursor <= m_limit); + assert(m_marker == nullptr or m_marker <= m_limit); + + // number of processed characters (p) + const auto num_processed_chars = static_cast(m_start - m_content); + // offset for m_marker wrt. to m_start + const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start; + // number of unprocessed characters (u) + const auto offset_cursor = m_cursor - m_start; + + // no stream is used or end of file is reached + if (m_stream == nullptr or m_stream->eof()) + { + // m_start may or may not be pointing into m_line_buffer at + // this point. We trust the standard library to do the right + // thing. See http://stackoverflow.com/q/28142011/266378 + m_line_buffer.assign(m_start, m_limit); + + // append n characters to make sure that there is sufficient + // space between m_cursor and m_limit + m_line_buffer.append(1, '\x00'); + if (n > 0) + { + m_line_buffer.append(n - 1, '\x01'); + } + } + else + { + // delete processed characters from line buffer + m_line_buffer.erase(0, num_processed_chars); + // read next line from input stream + m_line_buffer_tmp.clear(); + std::getline(*m_stream, m_line_buffer_tmp, '\n'); + + // add line with newline symbol to the line buffer + m_line_buffer += m_line_buffer_tmp; + m_line_buffer.push_back('\n'); + } + + // set pointers + m_content = reinterpret_cast(m_line_buffer.data()); + assert(m_content != nullptr); + m_start = m_content; + m_marker = m_start + offset_marker; + m_cursor = m_start + offset_cursor; + m_limit = m_start + m_line_buffer.size(); + } + + /// return string representation of last read token + string_t get_token_string() const + { + assert(m_start != nullptr); + return string_t(reinterpret_cast(m_start), + static_cast(m_cursor - m_start)); + } + + /*! + @brief return string value for string tokens + + The function iterates the characters between the opening and closing + quotes of the string value. The complete string is the range + [m_start,m_cursor). Consequently, we iterate from m_start+1 to + m_cursor-1. + + We differentiate two cases: + + 1. Escaped characters. In this case, a new character is constructed + according to the nature of the escape. Some escapes create new + characters (e.g., `"\\n"` is replaced by `"\n"`), some are copied + as is (e.g., `"\\\\"`). Furthermore, Unicode escapes of the shape + `"\\uxxxx"` need special care. In this case, to_unicode takes care + of the construction of the values. + 2. Unescaped characters are copied as is. + + @pre `m_cursor - m_start >= 2`, meaning the length of the last token + is at least 2 bytes which is trivially true for any string (which + consists of at least two quotes). + + " c1 c2 c3 ... " + ^ ^ + m_start m_cursor + + @complexity Linear in the length of the string.\n + + Lemma: The loop body will always terminate.\n + + Proof (by contradiction): Assume the loop body does not terminate. As + the loop body does not contain another loop, one of the called + functions must never return. The called functions are `std::strtoul` + and to_unicode. Neither function can loop forever, so the loop body + will never loop forever which contradicts the assumption that the loop + body does not terminate, q.e.d.\n + + Lemma: The loop condition for the for loop is eventually false.\n + + Proof (by contradiction): Assume the loop does not terminate. Due to + the above lemma, this can only be due to a tautological loop + condition; that is, the loop condition i < m_cursor - 1 must always be + true. Let x be the change of i for any loop iteration. Then + m_start + 1 + x < m_cursor - 1 must hold to loop indefinitely. This + can be rephrased to m_cursor - m_start - 2 > x. With the + precondition, we x <= 0, meaning that the loop condition holds + indefinitely if i is always decreased. However, observe that the value + of i is strictly increasing with each iteration, as it is incremented + by 1 in the iteration expression and never decremented inside the loop + body. Hence, the loop condition will eventually be false which + contradicts the assumption that the loop condition is a tautology, + q.e.d. + + @return string value of current token without opening and closing + quotes + @throw std::out_of_range if to_unicode fails + */ + string_t get_string() const + { + assert(m_cursor - m_start >= 2); + + string_t result; + result.reserve(static_cast(m_cursor - m_start - 2)); + + // iterate the result between the quotes + for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i) + { + // find next escape character + auto e = std::find(i, m_cursor - 1, '\\'); + if (e != i) + { + // see https://github.com/nlohmann/json/issues/365#issuecomment-262874705 + for (auto k = i; k < e; k++) + { + result.push_back(static_cast(*k)); + } + i = e - 1; // -1 because of ++i + } + else + { + // processing escaped character + // read next character + ++i; + + switch (*i) + { + // the default escapes + case 't': + { + result += "\t"; + break; + } + case 'b': + { + result += "\b"; + break; + } + case 'f': + { + result += "\f"; + break; + } + case 'n': + { + result += "\n"; + break; + } + case 'r': + { + result += "\r"; + break; + } + case '\\': + { + result += "\\"; + break; + } + case '/': + { + result += "/"; + break; + } + case '"': + { + result += "\""; + break; + } + + // unicode + case 'u': + { + // get code xxxx from uxxxx + auto codepoint = std::strtoul(std::string(reinterpret_cast(i + 1), + 4).c_str(), nullptr, 16); + + // check if codepoint is a high surrogate + if (codepoint >= 0xD800 and codepoint <= 0xDBFF) + { + // make sure there is a subsequent unicode + if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u') + { + JSON_THROW(std::invalid_argument("missing low surrogate")); + } + + // get code yyyy from uxxxx\uyyyy + auto codepoint2 = std::strtoul(std::string(reinterpret_cast + (i + 7), 4).c_str(), nullptr, 16); + result += to_unicode(codepoint, codepoint2); + // skip the next 10 characters (xxxx\uyyyy) + i += 10; + } + else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF) + { + // we found a lone low surrogate + JSON_THROW(std::invalid_argument("missing high surrogate")); + } + else + { + // add unicode character(s) + result += to_unicode(codepoint); + // skip the next four characters (xxxx) + i += 4; + } + break; + } + } + } + } + + return result; + } + + + /*! + @brief parse string into a built-in arithmetic type as if the current + locale is POSIX. + + @note in floating-point case strtod may parse past the token's end - + this is not an error + + @note any leading blanks are not handled + */ + struct strtonum + { + public: + strtonum(const char* start, const char* end) + : m_start(start), m_end(end) + {} + + /*! + @return true iff parsed successfully as number of type T + + @param[in,out] val shall contain parsed value, or undefined value + if could not parse + */ + template::value>::type> + bool to(T& val) const + { + return parse(val, std::is_integral()); + } + + private: + const char* const m_start = nullptr; + const char* const m_end = nullptr; + + // floating-point conversion + + // overloaded wrappers for strtod/strtof/strtold + // that will be called from parse + static void strtof(float& f, const char* str, char** endptr) + { + f = std::strtof(str, endptr); + } + + static void strtof(double& f, const char* str, char** endptr) + { + f = std::strtod(str, endptr); + } + + static void strtof(long double& f, const char* str, char** endptr) + { + f = std::strtold(str, endptr); + } + + template + bool parse(T& value, /*is_integral=*/std::false_type) const + { + // replace decimal separator with locale-specific version, + // when necessary; data will point to either the original + // string, or buf, or tempstr containing the fixed string. + std::string tempstr; + std::array buf; + const size_t len = static_cast(m_end - m_start); + + // lexer will reject empty numbers + assert(len > 0); + + // since dealing with strtod family of functions, we're + // getting the decimal point char from the C locale facilities + // instead of C++'s numpunct facet of the current std::locale + const auto loc = localeconv(); + assert(loc != nullptr); + const char decimal_point_char = (loc->decimal_point == nullptr) ? '.' : loc->decimal_point[0]; + + const char* data = m_start; + + if (decimal_point_char != '.') + { + const size_t ds_pos = static_cast(std::find(m_start, m_end, '.') - m_start); + + if (ds_pos != len) + { + // copy the data into the local buffer or tempstr, if + // buffer is too small; replace decimal separator, and + // update data to point to the modified bytes + if ((len + 1) < buf.size()) + { + std::copy(m_start, m_end, buf.begin()); + buf[len] = 0; + buf[ds_pos] = decimal_point_char; + data = buf.data(); + } + else + { + tempstr.assign(m_start, m_end); + tempstr[ds_pos] = decimal_point_char; + data = tempstr.c_str(); + } + } + } + + char* endptr = nullptr; + value = 0; + // this calls appropriate overload depending on T + strtof(value, data, &endptr); + + // parsing was successful iff strtof parsed exactly the number + // of characters determined by the lexer (len) + const bool ok = (endptr == (data + len)); + + if (ok and (value == static_cast(0.0)) and (*data == '-')) + { + // some implementations forget to negate the zero + value = -0.0; + } + + return ok; + } + + // integral conversion + + signed long long parse_integral(char** endptr, /*is_signed*/std::true_type) const + { + return std::strtoll(m_start, endptr, 10); + } + + unsigned long long parse_integral(char** endptr, /*is_signed*/std::false_type) const + { + return std::strtoull(m_start, endptr, 10); + } + + template + bool parse(T& value, /*is_integral=*/std::true_type) const + { + char* endptr = nullptr; + errno = 0; // these are thread-local + const auto x = parse_integral(&endptr, std::is_signed()); + + // called right overload? + static_assert(std::is_signed() == std::is_signed(), ""); + + value = static_cast(x); + + return (x == static_cast(value)) // x fits into destination T + and (x < 0) == (value < 0) // preserved sign + //and ((x != 0) or is_integral()) // strto[u]ll did nto fail + and (errno == 0) // strto[u]ll did not overflow + and (m_start < m_end) // token was not empty + and (endptr == m_end); // parsed entire token exactly + } + }; + + /*! + @brief return number value for number tokens + + This function translates the last token into the most appropriate + number type (either integer, unsigned integer or floating point), + which is passed back to the caller via the result parameter. + + integral numbers that don't fit into the the range of the respective + type are parsed as number_float_t + + floating-point values do not satisfy std::isfinite predicate + are converted to value_t::null + + throws if the entire string [m_start .. m_cursor) cannot be + interpreted as a number + + @param[out] result @ref basic_json object to receive the number. + @param[in] token the type of the number token + */ + bool get_number(basic_json& result, const token_type token) const + { + assert(m_start != nullptr); + assert(m_start < m_cursor); + assert((token == token_type::value_unsigned) or + (token == token_type::value_integer) or + (token == token_type::value_float)); + + strtonum num_converter(reinterpret_cast(m_start), + reinterpret_cast(m_cursor)); + + switch (token) + { + case lexer::token_type::value_unsigned: + { + number_unsigned_t val; + if (num_converter.to(val)) + { + // parsing successful + result.m_type = value_t::number_unsigned; + result.m_value = val; + return true; + } + break; + } + + case lexer::token_type::value_integer: + { + number_integer_t val; + if (num_converter.to(val)) + { + // parsing successful + result.m_type = value_t::number_integer; + result.m_value = val; + return true; + } + break; + } + + default: + { + break; + } + } + + // parse float (either explicitly or because a previous conversion + // failed) + number_float_t val; + if (num_converter.to(val)) + { + // parsing successful + result.m_type = value_t::number_float; + result.m_value = val; + + // replace infinity and NAN by null + if (not std::isfinite(result.m_value.number_float)) + { + result.m_type = value_t::null; + result.m_value = basic_json::json_value(); + } + + return true; + } + + // couldn't parse number in any format + return false; + } + + private: + /// optional input stream + std::istream* m_stream = nullptr; + /// line buffer buffer for m_stream + string_t m_line_buffer {}; + /// used for filling m_line_buffer + string_t m_line_buffer_tmp {}; + /// the buffer pointer + const lexer_char_t* m_content = nullptr; + /// pointer to the beginning of the current symbol + const lexer_char_t* m_start = nullptr; + /// pointer for backtracking information + const lexer_char_t* m_marker = nullptr; + /// pointer to the current symbol + const lexer_char_t* m_cursor = nullptr; + /// pointer to the end of the buffer + const lexer_char_t* m_limit = nullptr; + /// the last token type + token_type last_token_type = token_type::end_of_input; + }; + + /*! + @brief syntax analysis + + This class implements a recursive decent parser. + */ + class parser + { + public: + /// a parser reading from a string literal + parser(const char* buff, const parser_callback_t cb = nullptr) + : callback(cb), + m_lexer(reinterpret_cast(buff), std::strlen(buff)) + {} + + /// a parser reading from an input stream + parser(std::istream& is, const parser_callback_t cb = nullptr) + : callback(cb), m_lexer(is) + {} + + /// a parser reading from an iterator range with contiguous storage + template::iterator_category, std::random_access_iterator_tag>::value + , int>::type + = 0> + parser(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr) + : callback(cb), + m_lexer(reinterpret_cast(&(*first)), + static_cast(std::distance(first, last))) + {} + + /// public parser interface + basic_json parse() + { + // read first token + get_token(); + + basic_json result = parse_internal(true); + result.assert_invariant(); + + expect(lexer::token_type::end_of_input); + + // return parser result and replace it with null in case the + // top-level value was discarded by the callback function + return result.is_discarded() ? basic_json() : std::move(result); + } + + private: + /// the actual parser + basic_json parse_internal(bool keep) + { + auto result = basic_json(value_t::discarded); + + switch (last_token) + { + case lexer::token_type::begin_object: + { + if (keep and (not callback + or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0))) + { + // explicitly set result to object to cope with {} + result.m_type = value_t::object; + result.m_value = value_t::object; + } + + // read next token + get_token(); + + // closing } -> we are done + if (last_token == lexer::token_type::end_object) + { + get_token(); + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result = basic_json(value_t::discarded); + } + return result; + } + + // no comma is expected here + unexpect(lexer::token_type::value_separator); + + // otherwise: parse key-value pairs + do + { + // ugly, but could be fixed with loop reorganization + if (last_token == lexer::token_type::value_separator) + { + get_token(); + } + + // store key + expect(lexer::token_type::value_string); + const auto key = m_lexer.get_string(); + + bool keep_tag = false; + if (keep) + { + if (callback) + { + basic_json k(key); + keep_tag = callback(depth, parse_event_t::key, k); + } + else + { + keep_tag = true; + } + } + + // parse separator (:) + get_token(); + expect(lexer::token_type::name_separator); + + // parse and add value + get_token(); + auto value = parse_internal(keep); + if (keep and keep_tag and not value.is_discarded()) + { + result[key] = std::move(value); + } + } + while (last_token == lexer::token_type::value_separator); + + // closing } + expect(lexer::token_type::end_object); + get_token(); + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result = basic_json(value_t::discarded); + } + + return result; + } + + case lexer::token_type::begin_array: + { + if (keep and (not callback + or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0))) + { + // explicitly set result to object to cope with [] + result.m_type = value_t::array; + result.m_value = value_t::array; + } + + // read next token + get_token(); + + // closing ] -> we are done + if (last_token == lexer::token_type::end_array) + { + get_token(); + if (callback and not callback(--depth, parse_event_t::array_end, result)) + { + result = basic_json(value_t::discarded); + } + return result; + } + + // no comma is expected here + unexpect(lexer::token_type::value_separator); + + // otherwise: parse values + do + { + // ugly, but could be fixed with loop reorganization + if (last_token == lexer::token_type::value_separator) + { + get_token(); + } + + // parse value + auto value = parse_internal(keep); + if (keep and not value.is_discarded()) + { + result.push_back(std::move(value)); + } + } + while (last_token == lexer::token_type::value_separator); + + // closing ] + expect(lexer::token_type::end_array); + get_token(); + if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) + { + result = basic_json(value_t::discarded); + } + + return result; + } + + case lexer::token_type::literal_null: + { + get_token(); + result.m_type = value_t::null; + break; + } + + case lexer::token_type::value_string: + { + const auto s = m_lexer.get_string(); + get_token(); + result = basic_json(s); + break; + } + + case lexer::token_type::literal_true: + { + get_token(); + result.m_type = value_t::boolean; + result.m_value = true; + break; + } + + case lexer::token_type::literal_false: + { + get_token(); + result.m_type = value_t::boolean; + result.m_value = false; + break; + } + + case lexer::token_type::value_unsigned: + case lexer::token_type::value_integer: + case lexer::token_type::value_float: + { + m_lexer.get_number(result, last_token); + get_token(); + break; + } + + default: + { + // the last token was unexpected + unexpect(last_token); + } + } + + if (keep and callback and not callback(depth, parse_event_t::value, result)) + { + result = basic_json(value_t::discarded); + } + return result; + } + + /// get next token from lexer + typename lexer::token_type get_token() + { + last_token = m_lexer.scan(); + return last_token; + } + + void expect(typename lexer::token_type t) const + { + if (t != last_token) + { + std::string error_msg = "parse error - unexpected "; + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + + "'") : + lexer::token_type_name(last_token)); + error_msg += "; expected " + lexer::token_type_name(t); + JSON_THROW(std::invalid_argument(error_msg)); + } + } + + void unexpect(typename lexer::token_type t) const + { + if (t == last_token) + { + std::string error_msg = "parse error - unexpected "; + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + + "'") : + lexer::token_type_name(last_token)); + JSON_THROW(std::invalid_argument(error_msg)); + } + } + + private: + /// current level of recursion + int depth = 0; + /// callback function + const parser_callback_t callback = nullptr; + /// the type of the last read token + typename lexer::token_type last_token = lexer::token_type::uninitialized; + /// the lexer + lexer m_lexer; + }; + + public: + /*! + @brief JSON Pointer + + A JSON pointer defines a string syntax for identifying a specific value + within a JSON document. It can be used with functions `at` and + `operator[]`. Furthermore, JSON pointers are the base for JSON patches. + + @sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + + @since version 2.0.0 + */ + class json_pointer + { + /// allow basic_json to access private members + friend class basic_json; + + public: + /*! + @brief create JSON pointer + + Create a JSON pointer according to the syntax described in + [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). + + @param[in] s string representing the JSON pointer; if omitted, the + empty string is assumed which references the whole JSON + value + + @throw std::domain_error if reference token is nonempty and does not + begin with a slash (`/`); example: `"JSON pointer must be empty or + begin with /"` + @throw std::domain_error if a tilde (`~`) is not followed by `0` + (representing `~`) or `1` (representing `/`); example: `"escape error: + ~ must be followed with 0 or 1"` + + @liveexample{The example shows the construction several valid JSON + pointers as well as the exceptional behavior.,json_pointer} + + @since version 2.0.0 + */ + explicit json_pointer(const std::string& s = "") + : reference_tokens(split(s)) + {} + + /*! + @brief return a string representation of the JSON pointer + + @invariant For each JSON pointer `ptr`, it holds: + @code {.cpp} + ptr == json_pointer(ptr.to_string()); + @endcode + + @return a string representation of the JSON pointer + + @liveexample{The example shows the result of `to_string`., + json_pointer__to_string} + + @since version 2.0.0 + */ + std::string to_string() const noexcept + { + return std::accumulate(reference_tokens.begin(), + reference_tokens.end(), std::string{}, + [](const std::string & a, const std::string & b) + { + return a + "/" + escape(b); + }); + } + + /// @copydoc to_string() + operator std::string() const + { + return to_string(); + } + + private: + /// remove and return last reference pointer + std::string pop_back() + { + if (is_root()) + { + JSON_THROW(std::domain_error("JSON pointer has no parent")); + } + + auto last = reference_tokens.back(); + reference_tokens.pop_back(); + return last; + } + + /// return whether pointer points to the root document + bool is_root() const + { + return reference_tokens.empty(); + } + + json_pointer top() const + { + if (is_root()) + { + JSON_THROW(std::domain_error("JSON pointer has no parent")); + } + + json_pointer result = *this; + result.reference_tokens = {reference_tokens[0]}; + return result; + } + + /*! + @brief create and return a reference to the pointed to value + + @complexity Linear in the number of reference tokens. + */ + reference get_and_create(reference j) const + { + pointer result = &j; + + // in case no reference tokens exist, return a reference to the + // JSON value j which will be overwritten by a primitive value + for (const auto& reference_token : reference_tokens) + { + switch (result->m_type) + { + case value_t::null: + { + if (reference_token == "0") + { + // start a new array if reference token is 0 + result = &result->operator[](0); + } + else + { + // start a new object otherwise + result = &result->operator[](reference_token); + } + break; + } + + case value_t::object: + { + // create an entry in the object + result = &result->operator[](reference_token); + break; + } + + case value_t::array: + { + // create an entry in the array + result = &result->operator[](static_cast(std::stoi(reference_token))); + break; + } + + /* + The following code is only reached if there exists a + reference token _and_ the current value is primitive. In + this case, we have an error situation, because primitive + values may only occur as single value; that is, with an + empty list of reference tokens. + */ + default: + { + JSON_THROW(std::domain_error("invalid value to unflatten")); + } + } + } + + return *result; + } + + /*! + @brief return a reference to the pointed to value + + @note This version does not throw if a value is not present, but tries + to create nested values instead. For instance, calling this function + with pointer `"/this/that"` on a null value is equivalent to calling + `operator[]("this").operator[]("that")` on that value, effectively + changing the null value to an object. + + @param[in] ptr a JSON value + + @return reference to the JSON value pointed to by the JSON pointer + + @complexity Linear in the length of the JSON pointer. + + @throw std::out_of_range if the JSON pointer can not be resolved + @throw std::domain_error if an array index begins with '0' + @throw std::invalid_argument if an array index was not a number + */ + reference get_unchecked(pointer ptr) const + { + for (const auto& reference_token : reference_tokens) + { + // convert null values to arrays or objects before continuing + if (ptr->m_type == value_t::null) + { + // check if reference token is a number + const bool nums = std::all_of(reference_token.begin(), + reference_token.end(), + [](const char x) + { + return std::isdigit(x); + }); + + // change value to array for numbers or "-" or to object + // otherwise + if (nums or reference_token == "-") + { + *ptr = value_t::array; + } + else + { + *ptr = value_t::object; + } + } + + switch (ptr->m_type) + { + case value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case value_t::array: + { + // error condition (cf. RFC 6901, Sect. 4) + if (reference_token.size() > 1 and reference_token[0] == '0') + { + JSON_THROW(std::domain_error("array index must not begin with '0'")); + } + + if (reference_token == "-") + { + // explicitly treat "-" as index beyond the end + ptr = &ptr->operator[](ptr->m_value.array->size()); + } + else + { + // convert array index to number; unchecked access + ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); + } + break; + } + + default: + { + JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); + } + } + } + + return *ptr; + } + + reference get_checked(pointer ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case value_t::array: + { + if (reference_token == "-") + { + // "-" always fails the range check + JSON_THROW(std::out_of_range("array index '-' (" + + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (reference_token.size() > 1 and reference_token[0] == '0') + { + JSON_THROW(std::domain_error("array index must not begin with '0'")); + } + + // note: at performs range check + ptr = &ptr->at(static_cast(std::stoi(reference_token))); + break; + } + + default: + { + JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); + } + } + } + + return *ptr; + } + + /*! + @brief return a const reference to the pointed to value + + @param[in] ptr a JSON value + + @return const reference to the JSON value pointed to by the JSON + pointer + */ + const_reference get_unchecked(const_pointer ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case value_t::array: + { + if (reference_token == "-") + { + // "-" cannot be used for const access + JSON_THROW(std::out_of_range("array index '-' (" + + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (reference_token.size() > 1 and reference_token[0] == '0') + { + JSON_THROW(std::domain_error("array index must not begin with '0'")); + } + + // use unchecked array access + ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); + break; + } + + default: + { + JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); + } + } + } + + return *ptr; + } + + const_reference get_checked(const_pointer ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case value_t::array: + { + if (reference_token == "-") + { + // "-" always fails the range check + JSON_THROW(std::out_of_range("array index '-' (" + + std::to_string(ptr->m_value.array->size()) + + ") is out of range")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (reference_token.size() > 1 and reference_token[0] == '0') + { + JSON_THROW(std::domain_error("array index must not begin with '0'")); + } + + // note: at performs range check + ptr = &ptr->at(static_cast(std::stoi(reference_token))); + break; + } + + default: + { + JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); + } + } + } + + return *ptr; + } + + /// split the string input to reference tokens + static std::vector split(const std::string& reference_string) + { + std::vector result; + + // special case: empty reference string -> no reference tokens + if (reference_string.empty()) + { + return result; + } + + // check if nonempty reference string begins with slash + if (reference_string[0] != '/') + { + JSON_THROW(std::domain_error("JSON pointer must be empty or begin with '/'")); + } + + // extract the reference tokens: + // - slash: position of the last read slash (or end of string) + // - start: position after the previous slash + for ( + // search for the first slash after the first character + size_t slash = reference_string.find_first_of('/', 1), + // set the beginning of the first reference token + start = 1; + // we can stop if start == string::npos+1 = 0 + start != 0; + // set the beginning of the next reference token + // (will eventually be 0 if slash == std::string::npos) + start = slash + 1, + // find next slash + slash = reference_string.find_first_of('/', start)) + { + // use the text between the beginning of the reference token + // (start) and the last slash (slash). + auto reference_token = reference_string.substr(start, slash - start); + + // check reference tokens are properly escaped + for (size_t pos = reference_token.find_first_of('~'); + pos != std::string::npos; + pos = reference_token.find_first_of('~', pos + 1)) + { + assert(reference_token[pos] == '~'); + + // ~ must be followed by 0 or 1 + if (pos == reference_token.size() - 1 or + (reference_token[pos + 1] != '0' and + reference_token[pos + 1] != '1')) + { + JSON_THROW(std::domain_error("escape error: '~' must be followed with '0' or '1'")); + } + } + + // finally, store the reference token + unescape(reference_token); + result.push_back(reference_token); + } + + return result; + } + + private: + /*! + @brief replace all occurrences of a substring by another string + + @param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t + @param[in] f the substring to replace with @a t + @param[in] t the string to replace @a f + + @pre The search string @a f must not be empty. + + @since version 2.0.0 + */ + static void replace_substring(std::string& s, + const std::string& f, + const std::string& t) + { + assert(not f.empty()); + + for ( + size_t pos = s.find(f); // find first occurrence of f + pos != std::string::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t + pos = s.find(f, pos + t.size()) // find next occurrence of f + ); + } + + /// escape tilde and slash + static std::string escape(std::string s) + { + // escape "~"" to "~0" and "/" to "~1" + replace_substring(s, "~", "~0"); + replace_substring(s, "/", "~1"); + return s; + } + + /// unescape tilde and slash + static void unescape(std::string& s) + { + // first transform any occurrence of the sequence '~1' to '/' + replace_substring(s, "~1", "/"); + // then transform any occurrence of the sequence '~0' to '~' + replace_substring(s, "~0", "~"); + } + + /*! + @param[in] reference_string the reference string to the current value + @param[in] value the value to consider + @param[in,out] result the result object to insert values to + + @note Empty objects or arrays are flattened to `null`. + */ + static void flatten(const std::string& reference_string, + const basic_json& value, + basic_json& result) + { + switch (value.m_type) + { + case value_t::array: + { + if (value.m_value.array->empty()) + { + // flatten empty array as null + result[reference_string] = nullptr; + } + else + { + // iterate array and use index as reference string + for (size_t i = 0; i < value.m_value.array->size(); ++i) + { + flatten(reference_string + "/" + std::to_string(i), + value.m_value.array->operator[](i), result); + } + } + break; + } + + case value_t::object: + { + if (value.m_value.object->empty()) + { + // flatten empty object as null + result[reference_string] = nullptr; + } + else + { + // iterate object and use keys as reference string + for (const auto& element : *value.m_value.object) + { + flatten(reference_string + "/" + escape(element.first), + element.second, result); + } + } + break; + } + + default: + { + // add primitive value with its reference string + result[reference_string] = value; + break; + } + } + } + + /*! + @param[in] value flattened JSON + + @return unflattened JSON + */ + static basic_json unflatten(const basic_json& value) + { + if (not value.is_object()) + { + JSON_THROW(std::domain_error("only objects can be unflattened")); + } + + basic_json result; + + // iterate the JSON object values + for (const auto& element : *value.m_value.object) + { + if (not element.second.is_primitive()) + { + JSON_THROW(std::domain_error("values in object must be primitive")); + } + + // assign value to reference pointed to by JSON pointer; Note + // that if the JSON pointer is "" (i.e., points to the whole + // value), function get_and_create returns a reference to + // result itself. An assignment will then create a primitive + // value. + json_pointer(element.first).get_and_create(result) = element.second; + } + + return result; + } + + private: + friend bool operator==(json_pointer const& lhs, + json_pointer const& rhs) noexcept + { + return lhs.reference_tokens == rhs.reference_tokens; + } + + friend bool operator!=(json_pointer const& lhs, + json_pointer const& rhs) noexcept + { + return !(lhs == rhs); + } + + /// the reference tokens + std::vector reference_tokens {}; + }; + + ////////////////////////// + // JSON Pointer support // + ////////////////////////// + + /// @name JSON Pointer functions + /// @{ + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. Similar to @ref operator[](const typename + object_t::key_type&), `null` values are created in arrays and objects if + necessary. + + In particular: + - If the JSON pointer points to an object key that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. + - If the JSON pointer points to an array index that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. All indices between the current maximum and the given + index are also filled with `null`. + - The special value `-` is treated as a synonym for the index past the + end. + + @param[in] ptr a JSON pointer + + @return reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw std::out_of_range if the JSON pointer can not be resolved + @throw std::domain_error if an array index begins with '0' + @throw std::invalid_argument if an array index was not a number + + @liveexample{The behavior is shown in the example.,operatorjson_pointer} + + @since version 2.0.0 + */ + reference operator[](const json_pointer& ptr) + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. The function does not change the JSON + value; no `null` values are created. In particular, the the special value + `-` yields an exception. + + @param[in] ptr JSON pointer to the desired element + + @return const reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw std::out_of_range if the JSON pointer can not be resolved + @throw std::domain_error if an array index begins with '0' + @throw std::invalid_argument if an array index was not a number + + @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} + + @since version 2.0.0 + */ + const_reference operator[](const json_pointer& ptr) const + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a reference to the element at with specified JSON pointer @a ptr, + with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw std::out_of_range if the JSON pointer can not be resolved + @throw std::domain_error if an array index begins with '0' + @throw std::invalid_argument if an array index was not a number + + @liveexample{The behavior is shown in the example.,at_json_pointer} + + @since version 2.0.0 + */ + reference at(const json_pointer& ptr) + { + return ptr.get_checked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a const reference to the element at with specified JSON pointer @a + ptr, with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw std::out_of_range if the JSON pointer can not be resolved + @throw std::domain_error if an array index begins with '0' + @throw std::invalid_argument if an array index was not a number + + @liveexample{The behavior is shown in the example.,at_json_pointer_const} + + @since version 2.0.0 + */ + const_reference at(const json_pointer& ptr) const + { + return ptr.get_checked(this); + } + + /*! + @brief return flattened JSON value + + The function creates a JSON object whose keys are JSON pointers (see [RFC + 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all + primitive. The original JSON value can be restored using the @ref + unflatten() function. + + @return an object that maps JSON pointers to primitive values + + @note Empty objects and arrays are flattened to `null` and will not be + reconstructed correctly by the @ref unflatten() function. + + @complexity Linear in the size the JSON value. + + @liveexample{The following code shows how a JSON object is flattened to an + object whose keys consist of JSON pointers.,flatten} + + @sa @ref unflatten() for the reverse function + + @since version 2.0.0 + */ + basic_json flatten() const + { + basic_json result(value_t::object); + json_pointer::flatten("", *this, result); + return result; + } + + /*! + @brief unflatten a previously flattened JSON value + + The function restores the arbitrary nesting of a JSON value that has been + flattened before using the @ref flatten() function. The JSON value must + meet certain constraints: + 1. The value must be an object. + 2. The keys must be JSON pointers (see + [RFC 6901](https://tools.ietf.org/html/rfc6901)) + 3. The mapped values must be primitive JSON types. + + @return the original JSON from a flattened version + + @note Empty objects and arrays are flattened by @ref flatten() to `null` + values and can not unflattened to their original type. Apart from + this example, for a JSON value `j`, the following is always true: + `j == j.flatten().unflatten()`. + + @complexity Linear in the size the JSON value. + + @liveexample{The following code shows how a flattened JSON object is + unflattened into the original nested JSON object.,unflatten} + + @sa @ref flatten() for the reverse function + + @since version 2.0.0 + */ + basic_json unflatten() const + { + return json_pointer::unflatten(*this); + } + + /// @} + + ////////////////////////// + // JSON Patch functions // + ////////////////////////// + + /// @name JSON Patch functions + /// @{ + + /*! + @brief applies a JSON patch + + [JSON Patch](http://jsonpatch.com) defines a JSON document structure for + expressing a sequence of operations to apply to a JSON) document. With + this function, a JSON Patch is applied to the current JSON value by + executing all operations from the patch. + + @param[in] json_patch JSON patch document + @return patched document + + @note The application of a patch is atomic: Either all operations succeed + and the patched document is returned or an exception is thrown. In + any case, the original value is not changed: the patch is applied + to a copy of the value. + + @throw std::out_of_range if a JSON pointer inside the patch could not + be resolved successfully in the current JSON value; example: `"key baz + not found"` + @throw invalid_argument if the JSON patch is malformed (e.g., mandatory + attributes are missing); example: `"operation add must have member path"` + + @complexity Linear in the size of the JSON value and the length of the + JSON patch. As usually only a fraction of the JSON value is affected by + the patch, the complexity can usually be neglected. + + @liveexample{The following code shows how a JSON patch is applied to a + value.,patch} + + @sa @ref diff -- create a JSON patch by comparing two JSON values + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) + + @since version 2.0.0 + */ + basic_json patch(const basic_json& json_patch) const + { + // make a working copy to apply the patch to + basic_json result = *this; + + // the valid JSON Patch operations + enum class patch_operations {add, remove, replace, move, copy, test, invalid}; + + const auto get_op = [](const std::string op) + { + if (op == "add") + { + return patch_operations::add; + } + if (op == "remove") + { + return patch_operations::remove; + } + if (op == "replace") + { + return patch_operations::replace; + } + if (op == "move") + { + return patch_operations::move; + } + if (op == "copy") + { + return patch_operations::copy; + } + if (op == "test") + { + return patch_operations::test; + } + + return patch_operations::invalid; + }; + + // wrapper for "add" operation; add value at ptr + const auto operation_add = [&result](json_pointer & ptr, basic_json val) + { + // adding to the root of the target document means replacing it + if (ptr.is_root()) + { + result = val; + } + else + { + // make sure the top element of the pointer exists + json_pointer top_pointer = ptr.top(); + if (top_pointer != ptr) + { + result.at(top_pointer); + } + + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.pop_back(); + basic_json& parent = result[ptr]; + + switch (parent.m_type) + { + case value_t::null: + case value_t::object: + { + // use operator[] to add value + parent[last_path] = val; + break; + } + + case value_t::array: + { + if (last_path == "-") + { + // special case: append to back + parent.push_back(val); + } + else + { + const auto idx = std::stoi(last_path); + if (static_cast(idx) > parent.size()) + { + // avoid undefined behavior + JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); + } + else + { + // default case: insert add offset + parent.insert(parent.begin() + static_cast(idx), val); + } + } + break; + } + + default: + { + // if there exists a parent it cannot be primitive + assert(false); // LCOV_EXCL_LINE + } + } + } + }; + + // wrapper for "remove" operation; remove value at ptr + const auto operation_remove = [&result](json_pointer & ptr) + { + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.pop_back(); + basic_json& parent = result.at(ptr); + + // remove child + if (parent.is_object()) + { + // perform range check + auto it = parent.find(last_path); + if (it != parent.end()) + { + parent.erase(it); + } + else + { + JSON_THROW(std::out_of_range("key '" + last_path + "' not found")); + } + } + else if (parent.is_array()) + { + // note erase performs range check + parent.erase(static_cast(std::stoi(last_path))); + } + }; + + // type check + if (not json_patch.is_array()) + { + // a JSON patch must be an array of objects + JSON_THROW(std::invalid_argument("JSON patch must be an array of objects")); + } + + // iterate and apply the operations + for (const auto& val : json_patch) + { + // wrapper to get a value for an operation + const auto get_value = [&val](const std::string & op, + const std::string & member, + bool string_type) -> basic_json& + { + // find value + auto it = val.m_value.object->find(member); + + // context-sensitive error message + const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; + + // check if desired value is present + if (it == val.m_value.object->end()) + { + JSON_THROW(std::invalid_argument(error_msg + " must have member '" + member + "'")); + } + + // check if result is of type string + if (string_type and not it->second.is_string()) + { + JSON_THROW(std::invalid_argument(error_msg + " must have string member '" + member + "'")); + } + + // no error: return value + return it->second; + }; + + // type check + if (not val.is_object()) + { + JSON_THROW(std::invalid_argument("JSON patch must be an array of objects")); + } + + // collect mandatory members + const std::string op = get_value("op", "op", true); + const std::string path = get_value(op, "path", true); + json_pointer ptr(path); + + switch (get_op(op)) + { + case patch_operations::add: + { + operation_add(ptr, get_value("add", "value", false)); + break; + } + + case patch_operations::remove: + { + operation_remove(ptr); + break; + } + + case patch_operations::replace: + { + // the "path" location must exist - use at() + result.at(ptr) = get_value("replace", "value", false); + break; + } + + case patch_operations::move: + { + const std::string from_path = get_value("move", "from", true); + json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The move operation is functionally identical to a + // "remove" operation on the "from" location, followed + // immediately by an "add" operation at the target + // location with the value that was just removed. + operation_remove(from_ptr); + operation_add(ptr, v); + break; + } + + case patch_operations::copy: + { + const std::string from_path = get_value("copy", "from", true);; + const json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + result[ptr] = result.at(from_ptr); + break; + } + + case patch_operations::test: + { + bool success = false; + JSON_TRY + { + // check if "value" matches the one at "path" + // the "path" location must exist - use at() + success = (result.at(ptr) == get_value("test", "value", false)); + } + JSON_CATCH (std::out_of_range&) + { + // ignore out of range errors: success remains false + } + + // throw an exception if test fails + if (not success) + { + JSON_THROW(std::domain_error("unsuccessful: " + val.dump())); + } + + break; + } + + case patch_operations::invalid: + { + // op must be "add", "remove", "replace", "move", "copy", or + // "test" + JSON_THROW(std::invalid_argument("operation value '" + op + "' is invalid")); + } + } + } + + return result; + } + + /*! + @brief creates a diff as a JSON patch + + Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can + be changed into the value @a target by calling @ref patch function. + + @invariant For two JSON values @a source and @a target, the following code + yields always `true`: + @code {.cpp} + source.patch(diff(source, target)) == target; + @endcode + + @note Currently, only `remove`, `add`, and `replace` operations are + generated. + + @param[in] source JSON value to compare from + @param[in] target JSON value to compare against + @param[in] path helper value to create JSON pointers + + @return a JSON patch to convert the @a source to @a target + + @complexity Linear in the lengths of @a source and @a target. + + @liveexample{The following code shows how a JSON patch is created as a + diff for two JSON values.,diff} + + @sa @ref patch -- apply a JSON patch + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + + @since version 2.0.0 + */ + static basic_json diff(const basic_json& source, + const basic_json& target, + const std::string& path = "") + { + // the patch + basic_json result(value_t::array); + + // if the values are the same, return empty patch + if (source == target) + { + return result; + } + + if (source.type() != target.type()) + { + // different types: replace value + result.push_back( + { + {"op", "replace"}, + {"path", path}, + {"value", target} + }); + } + else + { + switch (source.type()) + { + case value_t::array: + { + // first pass: traverse common elements + size_t i = 0; + while (i < source.size() and i < target.size()) + { + // recursive call to compare array values at index i + auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + ++i; + } + + // i now reached the end of at least one array + // in a second pass, traverse the remaining elements + + // remove my remaining elements + const auto end_index = static_cast(result.size()); + while (i < source.size()) + { + // add operations in reverse order to avoid invalid + // indices + result.insert(result.begin() + end_index, object( + { + {"op", "remove"}, + {"path", path + "/" + std::to_string(i)} + })); + ++i; + } + + // add other remaining elements + while (i < target.size()) + { + result.push_back( + { + {"op", "add"}, + {"path", path + "/" + std::to_string(i)}, + {"value", target[i]} + }); + ++i; + } + + break; + } + + case value_t::object: + { + // first pass: traverse this object's elements + for (auto it = source.begin(); it != source.end(); ++it) + { + // escape the key name to be used in a JSON patch + const auto key = json_pointer::escape(it.key()); + + if (target.find(it.key()) != target.end()) + { + // recursive call to compare object values at key it + auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + } + else + { + // found a key that is not in o -> remove it + result.push_back(object( + { + {"op", "remove"}, + {"path", path + "/" + key} + })); + } + } + + // second pass: traverse other object's elements + for (auto it = target.begin(); it != target.end(); ++it) + { + if (source.find(it.key()) == source.end()) + { + // found a key that is not in this -> add it + const auto key = json_pointer::escape(it.key()); + result.push_back( + { + {"op", "add"}, + {"path", path + "/" + key}, + {"value", it.value()} + }); + } + } + + break; + } + + default: + { + // both primitive type: replace value + result.push_back( + { + {"op", "replace"}, + {"path", path}, + {"value", target} + }); + break; + } + } + } + + return result; + } + + /// @} +}; + +///////////// +// presets // +///////////// + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} // namespace nlohmann + + +/////////////////////// +// nonmember support // +/////////////////////// + +// specialization of std::swap, and std::hash +namespace std +{ +/*! +@brief exchanges the values of two JSON objects + +@since version 1.0.0 +*/ +template<> +inline void swap(nlohmann::json& j1, + nlohmann::json& j2) noexcept( + is_nothrow_move_constructible::value and + is_nothrow_move_assignable::value + ) +{ + j1.swap(j2); +} + +/// hash value for JSON objects +template<> +struct hash +{ + /*! + @brief return a hash value for a JSON object + + @since version 1.0.0 + */ + std::size_t operator()(const nlohmann::json& j) const + { + // a naive hashing via the string representation + const auto& h = hash(); + return h(j.dump()); + } +}; +} // namespace std + +/*! +@brief user-defined string literal for JSON values + +This operator implements a user-defined string literal for JSON objects. It +can be used by adding `"_json"` to a string literal and returns a JSON object +if no parse error occurred. + +@param[in] s a string representation of a JSON object +@param[in] n the length of string @a s +@return a JSON object + +@since version 1.0.0 +*/ +inline nlohmann::json operator "" _json(const char* s, std::size_t n) +{ + return nlohmann::json::parse(s, s + n); +} + +/*! +@brief user-defined string literal for JSON pointer + +This operator implements a user-defined string literal for JSON Pointers. It +can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer +object if no parse error occurred. + +@param[in] s a string representation of a JSON Pointer +@param[in] n the length of string @a s +@return a JSON pointer object + +@since version 2.0.0 +*/ +inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) +{ + return nlohmann::json::json_pointer(std::string(s, n)); +} + +// restore GCC/clang diagnostic settings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic pop +#endif + +// clean up +#undef JSON_CATCH +#undef JSON_DEPRECATED +#undef JSON_THROW +#undef JSON_TRY + +#endif diff --git a/src/menu.cxx b/src/menu.cxx new file mode 100644 index 0000000..af8e303 --- /dev/null +++ b/src/menu.cxx @@ -0,0 +1,516 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include +#include + +#include "blupi.h" +#include "button.h" +#include "decor.h" +#include "def.h" +#include "event.h" +#include "gettext.h" +#include "menu.h" +#include "misc.h" +#include "pixmap.h" +#include "sound.h" +#include "text.h" + +///////////////////////////////////////////////////////////////////////////// + +#define MARGMENU 0 + +static const Sint16 table_button_icon[] = { + 24, // go + 40, // stop + 32, // mange + 30, // carry + 31, // depose + 22, // abat + 27, // roc + 28, // cultive + 19, // build1 (cabane) + 25, // build2 (couveuse) + 35, // build3 (laboratoire) + 61, // build4 (mine) + 59, // build5 (usine) + 101, // build6 (téléporteur) + 20, // mur + 26, // palis + 42, // abat n + 43, // roc n + 23, // pont + 33, // tour + 34, // boit + 39, // labo + 54, // fleur + 55, // fleur n + 41, // dynamite + 58, // bateau + 60, // djeep + 64, // drapeau + 62, // extrait du fer + 65, // fabrique jeep + 63, // fabrique mine + 83, // fabrique disciple + 100, // repeat + 107, // qarmure + 106, // fabarmure +}; + +static const char * +GetText (Sint32 rank) +{ + static const char * list[] = { + translate ("Go"), + translate ("Stop"), + translate ("Eat"), + translate ("Take"), + translate ("Drop"), + translate ("Cut down a tree"), + translate ("Carve a rock"), + translate ("Grow tomatoes"), + translate ("Garden shed"), + translate ("Incubator"), + translate ("Laboratory"), + translate ("Mine"), + translate ("Workshop"), + translate ("Teleporter"), + translate ("Wall"), + translate ("Palisade"), + translate ("Cut down trees"), + translate ("Carve rocks"), + translate ("Bridge"), + translate ("Protection tower"), + translate ("Drink"), + translate ("Transform"), + translate ("Make bunch of flowers"), + translate ("Make bunches of flowers"), + translate ("Blow up"), + translate ("Boat"), + translate ("Leave Jeep"), + translate ("Prospect for iron"), + translate ("Extract iron"), + translate ("Make a Jeep"), + translate ("Make a time bomb"), + translate ("Make a helper robot"), + translate ("Repeat"), + translate ("Quit"), + translate ("Make armour"), + }; + + return gettext (list[rank]); +} + +static const char * +GetErr (Sint32 rank) +{ + static const char * list[] = { + translate ("Impossible"), translate ("Inadequate ground"), + translate ("Occupied ground"), translate ("Opposite bank no good"), + translate ("Bridge finished"), translate ("(isolated tower)"), + translate ("Too close to water"), translate ("Already two teleporters"), + translate ("Not enough energy")}; + + return gettext (list[rank]); +} + +///////////////////////////////////////////////////////////////////////////// + +// Constructeur. + +CMenu::CMenu () +{ + m_nbButtons = 0; + m_selRank = -1; + m_pPixmap = nullptr; + m_pDecor = nullptr; + m_pSound = nullptr; + m_pEvent = nullptr; +} + +// Destructeur. + +CMenu::~CMenu () {} + +// Crée un nouveau bouton. + +bool +CMenu::Create ( + CPixmap * pPixmap, CSound * pSound, CEvent * pEvent, Point pos, Sint32 nb, + Buttons * pButtons, Errors * pErrors, + std::unordered_map & texts, Sint32 perso) +{ + pos.x -= DIMBUTTONX / 2; + pos.y -= DIMBUTTONY / 2; + + m_pPixmap = pPixmap; + m_pSound = pSound; + m_pEvent = pEvent; + m_nbButtons = nb; + m_pos = pos; + m_perso = perso; + + Update (nb, pButtons, pErrors, texts); + + if (m_pos.x < POSDRAWX) + m_pos.x = POSDRAWX; + if (m_pos.y < POSDRAWY) + m_pos.y = POSDRAWY; + + if (m_pos.x > POSDRAWX + DIMDRAWX - 2 - m_dim.x) + m_pos.x = POSDRAWX + DIMDRAWX - 2 - m_dim.x; + if (m_pos.y > POSDRAWY + DIMDRAWY - 2 - m_dim.y) + m_pos.y = POSDRAWY + DIMDRAWY - 2 - m_dim.y; + + if (m_pos.x != pos.x || m_pos.y != pos.y) + { + pos = m_pos; + pos.x += DIMBUTTONX / 2; + pos.y += DIMBUTTONY / 2; + + this->m_pPixmap->FromGameToDisplay (pos.x, pos.y); + SDL_WarpMouseInWindow (g_window, pos.x, pos.y); + } + + m_selRank = Detect (pos); + + return true; +} + +// Met à jour le menu. + +void +CMenu::Update ( + Sint32 nb, Buttons * pButtons, Errors * pErrors, + std::unordered_map & texts) +{ + Sint32 i; + + m_nbButtons = nb; + + if (nb < 5) + m_nbCel.x = 1; + else + m_nbCel.x = 2; + + m_nbCel.y = (nb + m_nbCel.x - 1) / m_nbCel.x; + + m_dim.x = (DIMBUTTONX + MARGMENU) * m_nbCel.x; + m_dim.y = (DIMBUTTONY + MARGMENU) * m_nbCel.y; + + for (i = 0; i < nb; i++) + { + m_buttons[i] = pButtons[i]; + m_errors[i] = pErrors[i]; + } + m_texts = texts; +} + +// Détruit le menu. + +void +CMenu::Delete () +{ + m_nbButtons = 0; + m_selRank = -1; +} + +// Dessine un bouton dans son état. + +void +CMenu::Draw () +{ + Sint32 i, state, icon; + Point pos; + Rect oldClip, clipRect; + char text[50]; + char * pText; + + if (m_nbButtons == 0) + return; + + oldClip = m_pPixmap->GetClipping (); + clipRect.left = POSDRAWX; + clipRect.top = POSDRAWY; + clipRect.right = POSDRAWX + DIMDRAWX; + clipRect.bottom = POSDRAWY + DIMDRAWY; + m_pPixmap->SetClipping (clipRect); + + for (i = 0; i < m_nbButtons; i++) + { + pos.x = m_pos.x + ((i / m_nbCel.y) * (DIMBUTTONX + MARGMENU)); + pos.y = m_pos.y + ((i % m_nbCel.y) * (DIMBUTTONY + MARGMENU)); + + if (i == m_selRank) + state = 2; // hilite + else + state = 0; // release + if ( + m_errors[i] != 0 && m_errors[i] != Errors::TOURISOL && m_errors[i] < 100) + { + state = 4; // disable + } + m_pPixmap->DrawIcon (-1, CHBUTTON, state, pos); + + icon = table_button_icon[m_buttons[i]]; + if (IsRightReading () && icon == 40) + icon = 109; + if (m_perso == 8) // disciple ? + { + if (icon == 30) + icon = 88; // prend + if (icon == 31) + icon = 89; // dépose + } + m_pPixmap->DrawIcon (-1, CHBUTTON, icon + 6, pos); + } + + // Affiche le texte d'aide. + if (m_selRank != -1) + { + i = m_selRank; + pos.y = m_pos.y + ((i % m_nbCel.y) * (DIMBUTTONY + MARGMENU)); + + if (m_errors[i] == 0) + pos.y += (DIMBUTTONY - DIMTEXTY) / 2; + else + pos.y += (DIMBUTTONY - DIMTEXTY * 2) / 2; + + if (m_errors[i] >= 100) // no ressource au lieu erreur ? + { + snprintf (text, sizeof (text), "%s", m_texts[i]); + pText = strchr (text, '\n'); + if (pText != nullptr) + *pText = 0; + } + else + { + const auto tr = GetText (m_buttons[i]); + snprintf (text, sizeof (text), "%s", tr); + } + + if ( + (m_nbCel.x > 1 && i < m_nbCel.y) || (IsRightReading () && m_nbCel.x == 1)) + { + pos.x = m_pos.x - 4 - + (IsRightReading () ? 0 : GetTextWidth (text)); // texte à gauche + } + else + { + pos.x = + m_pos.x + m_dim.x + 4 + (IsRightReading () ? GetTextWidth (text) : 0); + } + + DrawText (m_pPixmap, pos, text, FONTWHITE); + + if (m_errors[i] != 0) + { + if (m_errors[i] >= 100) // no ressource au lieu erreur ? + { + snprintf (text, sizeof (text), "%s", m_texts[i]); + pText = strchr (text, '\n'); + if (pText != nullptr) + strcpy (text, pText + 1); + } + else + { + const auto tr = GetErr (m_errors[i] - 1); // impossible ici + snprintf (text, sizeof (text), "%s", tr); + } + + if ( + (m_nbCel.x > 1 && i < m_nbCel.y) || + (IsRightReading () && m_nbCel.x == 1)) + { + pos.x = m_pos.x - 4 - (IsRightReading () ? 0 : GetTextWidth (text)); + } + else + { + pos.x = + m_pos.x + m_dim.x + 4 + (IsRightReading () ? GetTextWidth (text) : 0); + } + + pos.y += DIMTEXTY; + if (m_errors[i] >= 100) // no ressource au lieu erreur ? + DrawText (m_pPixmap, pos, text, FONTWHITE); + else + DrawText (m_pPixmap, pos, text, FONTRED); + } + } + + m_pPixmap->SetClipping (oldClip); +} + +// Retourne le bouton sélectionné. + +Sint32 +CMenu::GetSel () +{ + if (m_selRank == -1) + return -1; + + return m_buttons[m_selRank]; +} + +// Retourne le rang sélectionné. + +Sint32 +CMenu::GetRank () +{ + return m_selRank; +} + +// Retourne true si le bouton sélectionné a une erreur. + +bool +CMenu::IsError () +{ + if (m_selRank == -1) + return true; + + if (m_errors[m_selRank] != 0 && m_errors[m_selRank] < 100) + return true; + + return false; +} + +// Indique si le menu existe. + +bool +CMenu::IsExist () +{ + return (m_nbButtons == 0) ? false : true; +} + +// Traitement d'un événement. + +bool +CMenu::TreatEvent (const SDL_Event & event) +{ + Point pos; + + if (m_nbButtons == 0) + return false; + + // pos = ConvLongToPos(lParam); + + switch (event.type) + { + case SDL_MOUSEBUTTONDOWN: + if ( + event.button.button != SDL_BUTTON_LEFT && + event.button.button != SDL_BUTTON_RIGHT) + break; + + pos.x = event.button.x; + pos.y = event.button.y; + if (MouseDown (pos)) + return true; + break; + + case SDL_MOUSEMOTION: + pos.x = event.motion.x; + pos.y = event.motion.y; + if (MouseMove (pos)) + return true; + break; + + case SDL_MOUSEBUTTONUP: + if ( + event.button.button != SDL_BUTTON_LEFT && + event.button.button != SDL_BUTTON_RIGHT) + break; + + pos.x = event.button.x; + pos.y = event.button.y; + if (MouseUp (pos)) + return true; + break; + } + + return false; +} + +// Détecte dans quel bouton est la souris. + +Sint32 +CMenu::Detect (Point pos) +{ + Sint32 rank; + + if ( + pos.x < m_pos.x || pos.x > m_pos.x + m_dim.x || pos.y < m_pos.y || + pos.y > m_pos.y + m_dim.y) + return -1; + + rank = (pos.y - m_pos.y) / (DIMBUTTONY + MARGMENU); + rank += ((pos.x - m_pos.x) / (DIMBUTTONX + MARGMENU)) * m_nbCel.y; + + if (rank >= m_nbButtons) + return -1; + return rank; +} + +// Bouton de la souris pressé. + +bool +CMenu::MouseDown (Point pos) +{ + return false; +} + +// Souris déplacés. + +bool +CMenu::MouseMove (Point pos) +{ + m_selRank = Detect (pos); + + if ( + pos.x < m_pos.x - (DIMBUTTONX + MARGMENU) || + pos.x > m_pos.x + m_dim.x + (DIMBUTTONX + MARGMENU) || + pos.y < m_pos.y - (DIMBUTTONY + MARGMENU) || + pos.y > m_pos.y + m_dim.y + (DIMBUTTONY + MARGMENU)) + { + Delete (); // enlève le menu si souris trop loin ! + } + + return false; +} + +// Bouton de la souris relâché. + +bool +CMenu::MouseUp (Point pos) +{ + m_selRank = Detect (pos); + + return false; +} + +// Envoie le message. + +void +CMenu::Message () +{ + if (m_selRank != -1) + CEvent::PushUserEvent (EV_BUTTON0 + m_selRank); +} diff --git a/src/menu.h b/src/menu.h new file mode 100644 index 0000000..ccd7c0f --- /dev/null +++ b/src/menu.h @@ -0,0 +1,75 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include + +#include "def.h" + +class CEvent; + +class CMenu +{ +public: + CMenu (); + ~CMenu (); + + bool Create ( + CPixmap * pPixmap, CSound * pSound, CEvent * pEvent, Point pos, Sint32 nb, + Buttons * pButtons, Errors * pErrors, + std::unordered_map & texts, Sint32 perso); + void Update ( + Sint32 nb, Buttons * pButtons, Errors * pErrors, + std::unordered_map & texts); + void Delete (); + void Draw (); + Sint32 GetSel (); + Sint32 GetRank (); + bool IsError (); + bool IsExist (); + void Message (); + + bool TreatEvent (const SDL_Event & event); + +protected: + Sint32 Detect (Point pos); + bool MouseDown (Point pos); + bool MouseMove (Point pos); + bool MouseUp (Point pos); + +protected: + CPixmap * m_pPixmap; + CDecor * m_pDecor; + CSound * m_pSound; + CEvent * m_pEvent; + Point m_pos; // up/left corner + Point m_dim; // dimensions + Sint32 m_nbButtons; + Point m_nbCel; + Sint32 m_perso; + Sint32 m_buttons[MAXBUTTON]; + Errors m_errors[MAXBUTTON]; + std::unordered_map m_texts; + Uint32 m_messages[MAXBUTTON]; + Sint32 m_selRank; +}; + +///////////////////////////////////////////////////////////////////////////// diff --git a/src/misc.cxx b/src/misc.cxx new file mode 100644 index 0000000..8c9d2e0 --- /dev/null +++ b/src/misc.cxx @@ -0,0 +1,213 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#define mkdir(a, b) _mkdir (a) +#else /* _WIN32 */ +#include +#endif /*! _WIN32 */ + +#include +#include + +#include "blupi.h" +#include "config.h" +#include "def.h" +#include "misc.h" + +// Affiche un message de debug. + +void +OutputDebug (const char * pMessage) +{ + SDL_LogDebug (SDL_LOG_CATEGORY_APPLICATION, "%s", pMessage); +} + +// Conversion de la position de la souris. + +Point +ConvLongToPos (LParam lParam) +{ + Point pos; + + pos.x = LOWORD (lParam); // horizontal position of cursor + pos.y = HIWORD (lParam); // vertical position of cursor + return pos; +} + +static int g_seed; + +/* Initialize the Microsoft pseudo-random generator */ +void +InitRandom () +{ + g_seed = 1; + // srand (1); +} + +/* We are not using rand from stdlib because on Linux the pseudo-generator + * is using an other algorithm. Then the behaviour is not the same on all + * platforms. + * See http://stackoverflow.com/a/1280765/842097 + */ +static int +ms_rand () +{ + g_seed = g_seed * 0x343fd + 0x269EC3; + return (g_seed >> 0x10) & 0x7FFF; +} + +/* Returns a random number between two values (included). */ +Sint32 +Random (Sint32 min, Sint32 max) +{ + Sint32 n; + + n = ms_rand (); // replace rand (); + n = min + (n % (max - min + 1)); + + return (Sint32) n; +} + +std::string +GetLocale () +{ + return gettext ("en"); +} + +bool +IsRightReading (const char * text) +{ + auto isRight = false; + if (text) + isRight = strchr (text, 0xD7) != nullptr; + else + isRight = GetLocale () == "he"; + return isRight; +} + +// Retourne le nom de dossier en cours. + +std::string +GetBaseDir () +{ + return GetShareDir () + "planetblupi/"; +} + +static std::string +GetDataDir () +{ + static std::string basePath; + + if (!basePath.size ()) + { + auto sdlBasePath = SDL_GetBasePath (); + + sdlBasePath[strlen (sdlBasePath) - 1] = '\0'; + + basePath = sdlBasePath; + + std::replace (basePath.begin (), basePath.end (), '\\', '/'); + basePath = basePath.substr (0, basePath.find_last_of ("//") + 1); + SDL_free (sdlBasePath); + } + + return basePath; +} + +std::string +GetShareDir () +{ + return GetDataDir () + "share/"; +} + +std::string +GetBinDir () +{ + std::string abs; + std::string bin = GetDataDir () + PB_BINDIR + "/"; + return bin; +} + +// Ajoute le chemin permettant de lire un fichier +// utilisateur. + +void +AddUserPath (std::string & pFilename) +{ + const char * pText; + size_t pos; + char last; + + char * temp = SDL_GetPrefPath ("Epsitec SA", "Planet Blupi"); + std::string path = temp; + + pText = strstr (pFilename.c_str (), "/"); + if (pText != nullptr) + { + pos = path.size () + (pText - pFilename.c_str ()) + 1; + path += pFilename; + last = path[pos]; + path[pos] = 0; + mkdir (path.c_str (), 0755); + path[pos] = last; + } + else + path += pFilename; + + pFilename = path; + SDL_free (temp); +} + +bool +FileExists ( + const std::string & filename, std::string & absolute, enum Location location) +{ + absolute = filename; + FILE * file; + + switch (location) + { + case LOCATION_BASE: + absolute = GetBaseDir () + filename; + break; + + case LOCATION_USER: + AddUserPath (absolute); + break; + + default: + case LOCATION_ABSOLUTE: + break; + } + + file = fopen (absolute.c_str (), "rb"); + if (file == nullptr) + return false; + + fclose (file); + return true; +} diff --git a/src/misc.h b/src/misc.h new file mode 100644 index 0000000..d3b7865 --- /dev/null +++ b/src/misc.h @@ -0,0 +1,80 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include +#include +#include +#ifdef __APPLE__ +#include +#endif /* __APPLE__ */ + +#include "blupi.h" + +extern void OutputDebug (const char * pMessage); + +extern Point ConvLongToPos (LParam lParam); + +extern void InitRandom (); +extern Sint32 Random (Sint32 min, Sint32 max); + +std::string GetBaseDir (); +std::string GetShareDir (); +std::string GetBinDir (); +std::string GetLocale (); +bool IsRightReading (const char * text = nullptr); +extern void AddUserPath (std::string & pFilename); + +enum Location { LOCATION_ABSOLUTE, LOCATION_BASE, LOCATION_USER }; +bool FileExists ( + const std::string & filename, std::string & absolute, + Location location = LOCATION_BASE); + +template +std::string +string_format (const std::string & format, Args... args) +{ + size_t size = snprintf (nullptr, 0, format.c_str (), args...) + 1; + std::unique_ptr buf (new char[size]); + snprintf (buf.get (), size, format.c_str (), args...); + return std::string (buf.get (), buf.get () + size - 1); +} + +#ifdef _WIN32 +static inline char * +basename (char * path) +{ + static char basename[_MAX_FNAME + _MAX_EXT]; + char fname[_MAX_FNAME]; + char ext[_MAX_EXT]; + _splitpath (path, nullptr, nullptr, fname, ext); + snprintf (basename, sizeof (basename), "%s%s", fname, ext); + return basename; +} +#endif /* _WIN32 */ +#ifdef EMSCRIPTEN +static inline char * +basename (char * filename) +{ + char * p = strrchr (filename, '/'); + return p ? p + 1 : filename; +} +#endif /* EMSCRIPTEN */ diff --git a/src/movie.cxx b/src/movie.cxx new file mode 100644 index 0000000..d0714ab --- /dev/null +++ b/src/movie.cxx @@ -0,0 +1,348 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include +#include +#include + +#include + +#include "kitchensink/kitchensink.h" + +#include "blupi.h" +#include "def.h" +#include "display.h" +#include "event.h" +#include "misc.h" +#include "movie.h" + +// Initialize avi libraries. + +bool +CMovie::initAVI () +{ + // Initialize Kitchensink with network support and all formats. + Sint32 err = Kit_Init (0); + if (err != 0) + { + fprintf (stderr, "Unable to initialize Kitchensink: %s", Kit_GetError ()); + return false; + } + + return true; +} + +// Closes the opened AVI file and the opened device type. | + +void +CMovie::termAVI () +{ + Kit_Quit (); +} + +// Close the movie and anything associated with it. | +// This function clears the and flags | + +void +CMovie::fileCloseMovie () +{ + m_fPlaying = false; // can't be playing any longer + m_fMovieOpen = false; // no more movies open + + if (m_videoTex) + { + SDL_DestroyTexture (m_videoTex); + m_videoTex = nullptr; + } + + if (this->backTexture) + { + SDL_DestroyTexture (this->backTexture); + this->backTexture = nullptr; + } + + if (m_player) + { + SDL_CloseAudioDevice (m_audioDev); + Kit_ClosePlayer (m_player); + m_player = nullptr; + } + + if (m_movie) + { + Kit_CloseSource (m_movie); + SDL_RWclose (this->rw_ops); + m_movie = nullptr; + } +} + +// Open an AVI movie. Use CommDlg open box to +// open and then handle the initialization to +// show the movie and position it properly. Keep +// the movie paused when opened. +// Sets on success. + +bool +CMovie::fileOpenMovie (const std::string & pFilename) +{ + const auto path = GetBaseDir () + pFilename; + + // we got a filename, now close any old movie and open the new one. */ + if (m_fMovieOpen) + fileCloseMovie (); + + this->rw_ops = SDL_RWFromFile (path.c_str (), "rb"); + if (!this->rw_ops) + return false; + + // Open up the sourcefile. + // This can be a local file, network url, ... + m_movie = Kit_CreateSourceFromRW (rw_ops); + if (m_movie) + { + // Create the player + m_player = Kit_CreatePlayer ( + m_movie, Kit_GetBestSourceStream (m_movie, KIT_STREAMTYPE_VIDEO), + Kit_GetBestSourceStream (m_movie, KIT_STREAMTYPE_AUDIO), + Kit_GetBestSourceStream (m_movie, KIT_STREAMTYPE_SUBTITLE), LXIMAGE (), + LYIMAGE ()); + if (m_player == nullptr) + return false; + + Kit_PlayerInfo info; + Kit_GetPlayerInfo (m_player, &info); + + SDL_AudioSpec wanted_spec, audio_spec; + + SDL_memset (&wanted_spec, 0, sizeof (wanted_spec)); + wanted_spec.freq = info.audio.output.samplerate; + wanted_spec.format = info.audio.output.format; + wanted_spec.channels = info.audio.output.channels; + m_audioDev = SDL_OpenAudioDevice (nullptr, 0, &wanted_spec, &audio_spec, 0); + SDL_PauseAudioDevice (m_audioDev, 0); + + if (g_bFullScreen && g_zoom == 1) + SDL_SetHint ( + SDL_HINT_RENDER_SCALE_QUALITY, g_renderQuality ? "best" : "nearest"); + m_videoTex = SDL_CreateTexture ( + g_renderer, info.video.output.format, SDL_TEXTUREACCESS_TARGET, + info.video.output.width, info.video.output.height); + if (g_bFullScreen && g_zoom == 1) + SDL_SetHint (SDL_HINT_RENDER_SCALE_QUALITY, "nearset"); + + if (m_videoTex == nullptr) + return false; + + std::string backWideName = ""; + if (Display::getDisplay ().isWide ()) + { + if (path.rfind ("win005.mkv") != std::string::npos) + backWideName = "image/back-disco.png"; + else if (path.rfind ("win129.mkv") != std::string::npos) + backWideName = "image/back-stars.png"; + } + + std::string file = GetBaseDir () + backWideName; + SDL_Surface * surface = IMG_Load (file.c_str ()); + this->backTexture = SDL_CreateTextureFromSurface (g_renderer, surface); + SDL_FreeSurface (surface); + + return true; + } + else + { + // generic error for open + m_fMovieOpen = false; + return false; + } +} + +// Play/pause the movie depending on the state + +void +CMovie::playMovie () +{ + m_fPlaying = !m_fPlaying; // swap the play flag + + // play/pause the AVI movie + if (m_fPlaying) + { + this->starting = true; + Kit_PlayerPlay (m_player); + } + else + Kit_PlayerPause (m_player); +} + +CMovie::CMovie (CPixmap * pixmap) +{ + this->pixmap = pixmap; + + m_bEnable = false; + m_fPlaying = false; + m_fMovieOpen = false; + + m_movie = nullptr; + m_player = nullptr; + m_videoTex = nullptr; + + memset (m_audiobuf, 0, sizeof (m_audiobuf)); + + this->rw_ops = nullptr; + + m_ret = 0; +} + +CMovie::~CMovie () +{ + termAVI (); +} + +// Ouvre la librairie avi. + +bool +CMovie::Create () +{ + m_bEnable = initAVI (); + return m_bEnable; +} + +// Retourne l'état de DirectMovie. + +bool +CMovie::GetEnable () +{ + return m_bEnable; +} + +// Montre un film avi. + +bool +CMovie::Play (const std::string & pFilename) +{ + if (!m_bEnable) + return false; + + if (!fileOpenMovie (pFilename)) + return false; + + playMovie (); + CEvent::PushUserEvent (EV_MOVIE_PLAY); + + return true; +} + +// Stoppe le film avi. + +void +CMovie::Stop () +{ + if (!m_bEnable) + return; + + fileCloseMovie (); +} + +void +CMovie::Pause () +{ + if (!m_bEnable || !m_fPlaying) + return; + + if (Kit_GetPlayerState (m_player) != KIT_PLAYING) + return; + + Kit_PlayerPause (m_player); +} + +void +CMovie::Resume () +{ + if (!m_bEnable || !m_fPlaying) + return; + + if (Kit_GetPlayerState (m_player) != KIT_PAUSED) + return; + + Kit_PlayerPlay (m_player); +} + +bool +CMovie::Render () +{ + if (!m_bEnable || !m_fPlaying) + return false; + + if (Kit_GetPlayerState (m_player) == KIT_STOPPED) + return false; + + // Refresh audio + if (SDL_GetQueuedAudioSize (m_audioDev) < AUDIOBUFFER_SIZE) + { + Sint32 need = AUDIOBUFFER_SIZE - m_ret; + + SDL_LockAudio (); + while (need > 0) + { + m_ret = Kit_GetPlayerAudioData ( + m_player, (unsigned char *) m_audiobuf, + AUDIOBUFFER_SIZE - (size_t) SDL_GetQueuedAudioSize (m_audioDev)); + need -= m_ret; + if (m_ret > 0) + SDL_QueueAudio (m_audioDev, m_audiobuf, m_ret); + else + break; + } + SDL_UnlockAudio (); + SDL_PauseAudioDevice (m_audioDev, 0); + } + + if (this->starting) + { + SDL_SetRenderTarget (g_renderer, m_videoTex); + SDL_SetRenderDrawColor (g_renderer, 0, 0, 0, 255); + SDL_RenderClear (g_renderer); + SDL_SetRenderTarget (g_renderer, nullptr); + this->starting = false; + } + + if (!this->backTexture) + { + // Clear screen with black + SDL_SetRenderDrawColor (g_renderer, 0, 0, 0, 255); + SDL_RenderClear (g_renderer); + } + else + SDL_RenderCopy (g_renderer, this->backTexture, nullptr, nullptr); + + // Refresh videotexture and render it + Kit_GetPlayerVideoData (m_player, m_videoTex); + + SDL_Rect dstRect; + dstRect.x = (LXIMAGE () - LXLOGIC ()) / 2; + dstRect.y = 0; + dstRect.w = LXLOGIC (); + dstRect.h = LYLOGIC (); + SDL_RenderCopy (g_renderer, m_videoTex, nullptr, &dstRect); + + SDL_RenderPresent (g_renderer); + CEvent::PushUserEvent (EV_MOVIE_PLAY); + return true; +} diff --git a/src/movie.h b/src/movie.h new file mode 100644 index 0000000..62837c8 --- /dev/null +++ b/src/movie.h @@ -0,0 +1,70 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include + +struct Kit_Source; +struct Kit_Player; +struct Kit_PlayerInfo; +struct SDL_Texture; +class CPixmap; + +#define AUDIOBUFFER_SIZE (32768) + +class CMovie +{ +public: + CMovie (CPixmap * pixmap); + ~CMovie (); + + bool Create (); + bool GetEnable (); + bool IsExist (const std::string & pFilename); + bool Play (const std::string & pFilename); + void Stop (); + void Pause (); + void Resume (); + bool Render (); + +protected: + void playMovie (); + bool fileOpenMovie (const std::string & pFilename); + void fileCloseMovie (); + void termAVI (); + bool initAVI (); + +protected: + CPixmap * pixmap; + Kit_Source * m_movie; + Kit_Player * m_player; + SDL_Texture * m_videoTex; + SDL_Texture * backTexture; + Sint32 m_ret; + SDL_AudioDeviceID m_audioDev; + SDL_RWops * rw_ops; + + char m_audiobuf[AUDIOBUFFER_SIZE]; + bool m_bEnable; + bool starting; + bool m_fPlaying; // Play flag: true == playing, false == paused + bool m_fMovieOpen; // Open flag: true == movie open, false = none +}; diff --git a/src/obstacle.cxx b/src/obstacle.cxx new file mode 100644 index 0000000..15ad199 --- /dev/null +++ b/src/obstacle.cxx @@ -0,0 +1,3816 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "action.h" +#include "decor.h" +#include "misc.h" + +// Cette table indique les obstacles sur les sols. +// 0=passage, 1=obstacle +// clang-format off +static char tableObstacleFloor[] = +{ + 1, 1, 1, 1, 1, // 0 (noir pour limites) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 0, 0, 0, 0, 0, // 1 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 1, 1, 1, 1, // 2 + 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, + + 0, 0, 0, 0, 0, // 3 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 0, // 4 + 1, 1, 1, 1, 0, + 1, 1, 1, 1, 0, + 1, 1, 1, 1, 0, + 1, 1, 1, 1, 0, + + 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 6 + 0, 0, 1, 1, 1, + 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, + + 0, 0, 0, 0, 0, // 7 + 1, 1, 1, 0, 0, + 1, 1, 1, 1, 0, + 1, 1, 1, 1, 0, + 1, 1, 1, 1, 0, + + 1, 1, 1, 1, 0, // 8 + 1, 1, 1, 1, 0, + 1, 1, 1, 1, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + 0, 1, 1, 1, 1, // 9 + 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, + + 0, 0, 1, 1, 1, // 10 + 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 0, 0, // 11 + 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 12 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, + 1, 1, 1, 0, 0, + + 1, 1, 1, 1, 1, // 13 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, + 0, 0, 1, 1, 1, + + 1, 1, 1, 1, 1, // 14 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 0, 0, 0, 0, 0, // 15 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 16 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 17 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 18 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 19 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 20 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 21 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 22 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 23 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 24 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 25 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 26 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 27 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 28 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 29 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 30 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 31 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 32 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 33 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 34 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 35 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 36 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 37 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 38 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 39 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 40 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 41 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 42 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 43 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 44 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 45 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 46 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 47 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 48 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 49 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 50 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 51 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 52 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 53 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 54 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 55 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 56 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 57 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 58 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 59 (pont e-o) + 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 0, 0, 0, 0, 0, // 60 + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 0, 0, 0, 0, 0, // 61 + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 0, 0, 0, 1, 1, // 62 (pont n-s) + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 1, 1, 1, // 63 + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 1, 1, 1, // 64 + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 0, 1, 1, +}; + +// Cette table indique les obstacles sur les sols pour le bateau. +// 0=passage, 1=obstacle + +static char tableObstacleFloorBateau[] = +{ + 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 0, 0, 1, 1, 1, // 4 + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 0, 0, 1, 1, 1, // 8 + 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 0, 0, // 10 + 1, 1, 1, 0, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 1, 1, 1, // 11 + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 12 + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 0, 0, 0, // 13 + 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 1, 1, 1, 0, 0, + 1, 1, 1, 0, 0, + + 0, 0, 0, 0, 0, // 14 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, +}; + +// Cette table indique les obstacles sur les objets. +// 0=passage, 1=obstacle + +static char tableObstacleObject[] = +{ + 0, 0, 0, 0, 0, // 0 + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 1 + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 2 + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 3 + 0, 1, 1, 1, 0, + 0, 1, 1, 1, 0, + 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 4 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 0, 0, 0, 0, 0, // 6 (arbre) + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 7 + 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, + 0, 0, 1, 1, 1, + 0, 0, 0, 1, 0, + + 0, 0, 0, 0, 0, // 8 + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 9 + 0, 0, 0, 1, 0, + 0, 0, 1, 1, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + 0, 1, 1, 1, 1, // 10 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 0, 1, 1, 1, 0, + + 1, 1, 1, 1, 0, // 11 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, + + 0, 1, 1, 1, 0, // 12 (fusée) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 0, 1, 1, 1, 0, + + 0, 0, 0, 0, 0, // 13 + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 14 (métal) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 1, 1, 1, 1, 1, // 15 (maison construction) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 0, 0, 0, 0, 0, // 16 (armure) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 1, 1, 1, 1, 1, // 17 (batiment ennemi) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 18 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + + 0, 0, 0, 0, 0, // 19 (électro piégé) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 1, 1, 1, 1, 1, // 20 (mur) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 21 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 22 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 23 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 24 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 25 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 26 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 27 (tour) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 28 (laboratoire) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, + 1, 1, 1, 1, 1, + // 1,1,1,1,1, // 28 (laboratoire) + // 1,1,1,1,1, + // 1,1,1,1,1, + // 1,1,1,1,1, + // 1,1,1,1,1, + + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 0, 0, 0, 0, 0, // 30 (arbre sans feuilles) + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 31 + 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, + 0, 0, 1, 1, 1, + 0, 0, 0, 1, 0, + + 0, 0, 0, 0, 0, // 32 + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 33 + 0, 0, 0, 1, 0, + 0, 0, 1, 1, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, + + 0, 1, 1, 1, 1, // 34 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 0, 1, 1, 1, 0, + + 1, 1, 1, 1, 0, // 35 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, + + 0, 0, 0, 0, 0, // 36 (tas de planches) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 1, 1, 1, 1, 1, // 37 (rochers) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 38 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 39 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 40 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 41 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 42 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 43 + 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 44 (tas de pierres) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 0, 0, 0, // 45 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 46 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 47 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 48 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 49 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 50 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 51 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 52 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 53 + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 0, 0, 0, // 54 + 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 1, 1, 1, 0, 0, + 1, 1, 1, 0, 0, + + 1, 1, 1, 0, 0, // 55 + 1, 1, 1, 0, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 1, 1, 1, // 56 + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 57 (plante) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 0, 0, 0, // 58 + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 0, 0, 0, // 59 + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 0, 0, 0, // 60 (tomates) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 1, 1, 1, 1, 1, // 61 (cabane) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 62 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 0, 0, 0, 0, 0, // 63 (oeufs) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 1, 1, 1, 1, 1, // 64 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 0, // 65 (palissade) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, + 0, 1, 1, 0, 0, + + 1, 1, 1, 1, 0, // 66 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, + 0, 1, 1, 0, 0, + + 1, 1, 1, 1, 0, // 67 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, + 0, 1, 1, 0, 0, + + 1, 1, 1, 1, 0, // 68 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, + 0, 1, 1, 0, 0, + + 1, 1, 1, 1, 0, // 69 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, + 0, 1, 1, 0, 0, + + 1, 1, 1, 1, 0, // 70 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, + 0, 1, 1, 0, 0, + + 1, 1, 1, 1, 0, // 71 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, + 0, 1, 1, 0, 0, + + 0, 0, 0, 0, 0, // 72 (pont en construction) + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 73 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 74 (rayon tour) + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 75 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 76 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 77 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 78 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 79 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 80 (bouteille) + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + 0, 1, 1, 1, 0, // 81 (fleurs) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 0, 1, 1, 1, 0, + + 0, 0, 0, 0, 0, // 82 + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 1, 1, 1, 0, // 83 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 0, 1, 1, 1, 0, + + 0, 0, 0, 0, 0, // 84 + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 0, 0, 0, // 85 (dynamite) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 0, 0, 0, // 86 + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 0, 0, 0, // 87 + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 0, 0, 0, // 88 (explosion) + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 89 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 90 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 91 + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 92 (poison) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 0, 0, 0, // 93 (piège) + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, + + 0, 1, 1, 1, 0, // 94 (fleurs) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 0, 1, 1, 1, 0, + + 0, 0, 0, 0, 0, // 95 + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 0, 0, 0, // 96 (araignée dans piège) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 0, 0, 0, // 97 (tracks dans piège) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 0, 0, 0, // 98 (robot dans piège) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 1, 1, 1, 1, 1, // 99 (recharge) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, + 1, 1, 1, 0, 0, + + 1, 1, 1, 1, 1, // 100 (batiment ennemi) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 101 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 102 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 103 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 104 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 105 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 106 (barrière) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 107 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 108 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 109 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 110 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 111 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 112 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 113 (maison) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, + 1, 1, 1, 1, 1, + + 0, 0, 0, 0, 0, // 114 (bombe dans piège) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 1, 1, 1, 1, 1, // 115 (batiment ennemi) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 116 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + + 0, 0, 0, 0, 0, // 117 (bateau) + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 118 (jeep) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 1, 1, 1, 1, 1, // 119 (usine) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 120 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 0, 0, 0, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 121 (mine de fer) + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, // 122 + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, + 1, 1, 1, 1, 1, + + 0, 0, 0, 0, 0, // 123 (fer) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 0, 0, 0, // 124 (drapeau) + 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 125 (mine) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + + 0, 0, 0, 0, 0, // 126 (mine de fer, échaffaudage) + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, // 127 (mine) + 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, +}; +// clang-format on + +// Retourne les obstacles autour d'une cellule, sous la +// forme d'un tableau de 3x3. + +void +CDecor::SearchFloor (Sint32 rank, Sint32 icon, Point cel, Sint32 * pBits) +{ + char * pTable; + Sint32 first, last; + Sint32 dx, dy, x, y, i; + Sint32 def = 0; + + pTable = tableObstacleFloor; + first = 0; + last = 64; + + if (rank != -1 && m_blupi[rank].vehicule == 1) // en bateau ? + { + pTable = tableObstacleFloorBateau; + first = 2; + last = 14; + def = 1; + } + + if (icon >= first && icon <= last) + { + pTable += (icon - first) * 5 * 5; + + if (cel.x % 2 == 0) + dx = 0; + else + dx = 2; + + if (cel.y % 2 == 0) + dy = 0; + else + dy = 2; + + for (y = dy; y < dy + 3; y++) + { + for (x = dx; x < dx + 3; x++) + *pBits++ = pTable[x + y * 5]; + } + } + else + { + for (i = 0; i < 9; i++) + *pBits++ = def; + } +} + +// Retourne les obstacles autour d'une cellule, sous la +// forme d'un tableau de 3x3. + +void +CDecor::SearchObject (Sint32 rank, Sint32 icon, Point cel, Sint32 * pBits) +{ + char * pTable; + Sint32 dx, dy, x, y, i; + + if (icon >= 0 && icon <= 127) + { + pTable = tableObstacleObject + (icon) *5 * 5; + + if (cel.x % 2 == 0) + dx = 0; + else + dx = 2; + + if (cel.y % 2 == 0) + dy = 0; + else + dy = 2; + + for (y = dy; y < dy + 3; y++) + { + for (x = dx; x < dx + 3; x++) + *pBits++ = pTable[x + y * 5]; + } + } + else + { + for (i = 0; i < 9; i++) + *pBits++ = 0; + } +} + +// Ajuste un sol en fonction du personnage. + +void +CDecor::AjustFloor (Sint32 rank, Sint32 icon, Point cel, Sint32 * pBits) +{ + Sint32 i; + + if (rank < 0) + return; + + if (m_blupi[rank].perso == 0) // blupi ? + { + if (m_blupi[rank].interrupt == -1) // passe muraille (*) ? + goto pass; + if (m_blupi[rank].vehicule == 1) // en bateau ? + { + if (icon >= 59 && icon <= 64) + goto lock; // pont ? + } + return; + } + + if (m_blupi[rank].perso == 2) // virus ? + { + goto pass; // le virus peut aller partout (il volle) + return; + } + + if (m_blupi[rank].perso == 3) // tracks ? + { + if (icon >= 59 && icon <= 64) // ponts ? + { + goto lock; // le tracks ne peut pas aller sur les ponts + } + return; + } + + //- if ( m_blupi[rank].perso == 4 ) // robot ? + //- { + //- if ( icon >= 59 && icon <= 64 ) // ponts ? + //- { + //- goto lock; // le robot ne peut pas aller sur les ponts + //- } + //- return; + //- } + return; + +pass: + for (i = 0; i < 9; i++) + { + *pBits++ = 0; // peut passer + } + return; + +lock: + for (i = 0; i < 9; i++) + { + *pBits++ = 1; // bloqué + } + return; +} + +// Ajuste un obstacle en fonction du personnage. + +void +CDecor::AjustObject (Sint32 rank, Sint32 icon, Point cel, Sint32 * pBits) +{ + Sint32 i; + + if (rank < 0) + return; + + if (m_blupi[rank].perso == 0) // blupi ? + { + if ( + m_blupi[rank].vehicule != 0 && // pas à pied ? + cel.x % 2 == 1 && cel.y % 2 == 1 && + m_decor[cel.x / 2][cel.y / 2].objectIcon == 117) // bateau ? + { + goto lock; // blupi ne peut pas aller dans le bateau + } + + if ( + cel.x % 2 == 1 && cel.y % 2 == 1 && + m_decor[cel.x / 2][cel.y / 2].objectIcon == 99) // recharge ? + { + goto lock; // blupi ne peut pas bloquer la station + } + if ( + m_blupi[rank].vehicule == 2 && // en jeep ? + m_decor[cel.x / 2][cel.y / 2].objectIcon == 113) // maison ? + { + goto lock; // blupi ne peut pas aller dans la maison + } + return; + } + + if (m_blupi[rank].perso == 1) // araignée ? + { + // if ( cel.x%2 != 0 && cel.y%2 != 0 && + if (IsSpiderObject (icon)) // tomate ou poison ? + { + goto pass; // l'araignée peut aller dans les tomates + } + return; + } + + if (m_blupi[rank].perso == 2) // virus ? + { + if ( + icon == 81 || icon == 83 || icon == 94 || // fleurs non-coupées ? + (icon >= 106 && icon <= 112)) // barrières ennemies ? + { + goto pass; // le virus peut aller + } + return; + } + + if (m_blupi[rank].perso == 3) // tracks ? + { + if (IsTracksObject (icon)) // fleurs ou objet ? + { + goto pass; // le tracks peut aller + } + if ( + icon == 113 || // maison ? + icon == 28 || icon == 29 || // laboratoire ? + icon == 119 || icon == 120 || // usine ? + icon == 121 || icon == 122) // mine de fer ? + { + goto lock; // le tracks ne peut pas aller dans la maison + } + return; + } + + if (m_blupi[rank].perso == 4) // robot ? + { + if (IsRobotObject (icon)) // piège ou dynamite ? + { + goto pass; // le robot peut aller + } + return; + } + + if (m_blupi[rank].perso == 5) // bombe ? + { + if (icon == 93) // piège ? + { + goto pass; // la bombe peut aller + } + return; + } + + if (m_blupi[rank].perso == 7) // électro ? + { + if (icon == 93) // piège ? + { + goto pass; // l'électro peut aller + } + if ( + icon == 113 || // maison ? + icon == 28 || icon == 29 || // laboratoire ? + icon == 119 || icon == 120 || // usine ? + icon == 121 || icon == 122) // mine de fer ? + { + goto lock; // l'électro ne peut pas aller dans la maison + } + return; + } + + if (m_blupi[rank].perso == 8) // disciple ? + { + if ( + cel.x > 0 && cel.x % 2 == 0 && cel.y % 2 == 1 && + (m_decor[(cel.x - 2) / 2][cel.y / 2].objectIcon == 17 || // factory + m_decor[(cel.x - 2) / 2][cel.y / 2].objectIcon == 100 || + m_decor[(cel.x - 2) / 2][cel.y / 2].objectIcon == 102 || + m_decor[(cel.x - 2) / 2][cel.y / 2].objectIcon == 104 || + m_decor[(cel.x - 2) / 2][cel.y / 2].objectIcon == 115)) + { + goto lock; // disciple ne peut pas bloquer la porte + } + if ( + cel.x % 2 == 1 && cel.y % 2 == 1 && + m_decor[cel.x / 2][cel.y / 2].objectIcon == 99) // recharge ? + { + goto lock; // disciple ne peut pas bloquer la station + } + if (m_decor[cel.x / 2][cel.y / 2].objectIcon == 113) // maison ? + { + goto lock; // disciple ne peut pas aller dans la maison + } + return; + } + return; + +pass: + for (i = 0; i < 9; i++) + { + *pBits++ = 0; // peut passer + } + return; + +lock: + for (i = 0; i < 9; i++) + { + *pBits++ = 1; // bloqué + } + return; +} + +// Copie un tableau 3x3 dans un tableau 9x9. + +void +Copy33To99 (Sint32 * pSrc33, Sint32 * pDst99, Sint32 dx, Sint32 dy) +{ + Sint32 x, y; + + for (y = 0; y < 3; y++) + { + for (x = 0; x < 3; x++) + pDst99[(dx + 1) * 3 + x + ((dy + 1) * 3 + y) * 9] = pSrc33[x + y * 3]; + } +} + +// Indique s'il est possible d'avancer dans une direction donnée. + +bool +CDecor::IsFreeDirect (Point cel, Sint32 direct, Sint32 rank) +{ + Sint32 icon, workBlupi; + Sint32 bits[3 * 3], obstacles[9 * 9]; + Point test, vector; + + vector = GetVector (direct); + + test.x = cel.x + vector.x; + test.y = cel.y + vector.y; + + if ( + m_decor[test.x / 2][test.y / 2].fire > 0 && + m_decor[test.x / 2][test.y / 2].fire < MoveMaxFire ()) + return false; + + // Cellule bloquée (un blupi travaille ici) ? + if (m_blupi[rank].perso != 3) // pas tracks ? + { + workBlupi = m_decor[test.x / 2][test.y / 2].workBlupi; + if (workBlupi >= 0 && workBlupi != rank) + return false; + } + + // Déplacement possible par-rapport au sol ? + // icon = m_decor[cel.x/2][cel.y/2].floorIcon; + // SearchFloor(rank, icon, cel, bits); + // AjustFloor(rank, icon, cel, bits); + // if ( bits[(1+vector.x)+(1+vector.y)*3] == 1 ) return false; + + icon = m_decor[test.x / 2][test.y / 2].floorIcon; + SearchFloor (rank, icon, test, bits); + AjustFloor (rank, icon, test, bits); + if (bits[1 + 1 * 3] == 1) + return false; + if (bits[(1 - vector.x) + (1 - vector.y) * 3] == 1) + return false; + + // Déplacement possible par-rapport aux obstacles ? + icon = m_decor[cel.x / 2][cel.y / 2].objectIcon; + SearchObject (rank, icon, cel, bits); + AjustObject (rank, icon, cel, bits); + if (bits[(1 + vector.x) + (1 + vector.y) * 3] == 1) + return false; + + icon = m_decor[test.x / 2][test.y / 2].objectIcon; + SearchObject (rank, icon, test, bits); + AjustObject (rank, icon, test, bits); + if (bits[(1 - vector.x) + (1 - vector.y) * 3] == 1) + return false; + if (bits[1 + 1 * 3] == 1) + return false; + + if (vector.x != 0 && vector.y != 0) // déplacement diagonal ? + { + test.x = cel.x; + test.y = cel.y + vector.y; + icon = m_decor[test.x / 2][test.y / 2].objectIcon; + SearchObject (rank, icon, test, bits); + AjustObject (rank, icon, test, bits); + Copy33To99 (bits, obstacles, 0, vector.y); + + test.x = cel.x + vector.x; + test.y = cel.y; + icon = m_decor[test.x / 2][test.y / 2].objectIcon; + SearchObject (rank, icon, test, bits); + AjustObject (rank, icon, test, bits); + Copy33To99 (bits, obstacles, vector.x, 0); + + if (obstacles[(4 + vector.x * 1) + (4 + vector.y * 2) * 9] == 1) + return false; + if (obstacles[(4 + vector.x * 2) + (4 + vector.y * 1) * 9] == 1) + return false; + } + + return true; // pas d'obstacle +} + +// Indique si une cellule contient un objet. +// Est utilisé lors du dessin (BuildPutBlupi), pour savoir +// si blupi est devant un objet. + +bool +CDecor::IsFreeCelObstacle (Point cel) +{ + Sint32 icon; + Sint32 bits[9]; + + if (!IsValid (cel)) + return false; + + if ( + m_decor[cel.x / 2][cel.y / 2].fire > 0 && + m_decor[cel.x / 2][cel.y / 2].fire < MoveMaxFire ()) + return false; + + icon = m_decor[cel.x / 2][cel.y / 2].objectIcon; + if (icon != -1) + { + SearchObject (-1, icon, cel, bits); + if (bits[1 + 1 * 3] == 1) + return false; + } + + return true; // pas d'obstacle +} + +// Indique si une cellule contient un sol. +// Est utilisé pour savoir si blupi peut aller sur une cellule +// en tenant compte uniquement des sols. +// Retourne true si blupi peut y aller ! + +bool +CDecor::IsFreeCelFloor (Point cel, Sint32 rank) +{ + Sint32 icon; + Sint32 bits[9]; + + if (!IsValid (cel)) + return false; + + icon = m_decor[cel.x / 2][cel.y / 2].floorIcon; + if (icon != -1) + { + SearchFloor (rank, icon, cel, bits); + AjustFloor (rank, icon, cel, bits); + if (bits[1 + 1 * 3] == 1) + return false; + } + + return true; // pas d'obstacle +} + +// Indique si une cellule est libre. +// Est utilisé pour savoir si blupi peut venir ici +// débarquer en bateau ou monter dans sa jeep. + +bool +CDecor::IsFreeCelGo (Point cel, Sint32 rank) +{ + bool bOK; + Point limit; + Sint32 action, channel, icon; + + if (rank == -1) + return IsFreeCel (cel, rank); + + GetObject (cel, channel, icon); + + // Refuse d'aller dans la maison si blupi porte qq chose. + if ( + m_blupi[rank].takeChannel != -1 && // porte qq chose ? + channel == CHOBJECT && icon == 113) // maison ? + return false; + + // Refuse d'aller dans le laboratoire (on peut seulement + // y transformer qq chose). + if ( + channel == CHOBJECT && (icon == 28 || // laboratoire ? + icon == 120 || // usine ? + icon == 122)) // mine de fer ? + return false; + + // Refuse to go in an enemy factory when the door is open. + if ( + !g_restoreBugs && channel == CHOBJECT && + (icon == 18 || icon == 101 || icon == 103 || icon == 105 || icon == 116)) + return false; + + bOK = IsFreeCel (cel, rank); + if (bOK) + return true; + + bOK = IsFreeCelEmbarque (cel, rank, action, limit); + if (bOK) + return true; + + bOK = IsFreeCelDebarque (cel, rank, action, limit); + if (bOK) + return true; + + if ( + !m_blupi[rank].bMalade && m_blupi[rank].vehicule == 0 && // à pied ? + m_blupi[rank].perso != 8 && // pas le disciple ? + channel == CHOBJECT && icon == 118) // jeep ? + return true; + + if ( + !m_blupi[rank].bMalade && m_blupi[rank].vehicule == 0 && // à pied ? + m_blupi[rank].perso != 8 && // pas le disciple ? + m_blupi[rank].energy > MAXENERGY / 4 && // fort ? + m_blupi[rank].takeChannel == -1 && // porte rien ? + channel == CHOBJECT && icon == 16) // armure ? + return true; + + return false; +} + +// Indique si on peut faire qq chose sur une cellule. +// Est utilisé pour savoir comment est la mise en évidence (hili) +// à cet endroit. + +bool +CDecor::IsFreeCelHili (Point cel, Sint32 rank) +{ + bool bOK; + Point limit; + Sint32 workBlupi, channel, icon, action; + + if (IsValid (cel)) + { + workBlupi = m_decor[cel.x / 2][cel.y / 2].workBlupi; + if (workBlupi >= 0 && workBlupi != rank) + return false; + + channel = m_decor[cel.x / 2][cel.y / 2].objectChannel; + icon = m_decor[cel.x / 2][cel.y / 2].objectIcon; + + if ( + channel == CHOBJECT && + (icon == 12 || // fusée ? + (icon >= 20 && icon <= 26) || // mur ? + (icon >= 106 && icon <= 112) || // barrière ? + (icon >= 99 && icon <= 105) || // batiment ennemi ? + (icon >= 115 && icon <= 116) || // idem ? + (icon >= 17 && icon <= 18))) // idem ? + return false; + } + + if (rank == -1) + return IsFreeCelFloor (cel, rank); + + bOK = IsFreeCelFloor (cel, rank); + if (bOK) + return true; + + bOK = IsFreeCelEmbarque (cel, rank, action, limit); + if (bOK) + return true; + + bOK = IsFreeCelDebarque (cel, rank, action, limit); + if (bOK) + return true; + + return false; +} + +// Indique si une cellule est libre. +// Est utilisé pour savoir si blupi peut venir ici. + +bool +CDecor::IsFreeCel (Point cel, Sint32 rank) +{ + Sint32 icon, workBlupi; + Sint32 bits[9]; + + if (!IsValid (cel)) + return false; + + if ( + m_decor[cel.x / 2][cel.y / 2].fire > 0 && + m_decor[cel.x / 2][cel.y / 2].fire < MoveMaxFire ()) + return false; + + // Cellule bloquée (un blupi travaille ici) ? + if (rank != -1 && m_blupi[rank].perso != 3) // pas tracks ? + { + workBlupi = m_decor[cel.x / 2][cel.y / 2].workBlupi; + if (workBlupi >= 0 && workBlupi != rank) + return false; + } + + icon = m_decor[cel.x / 2][cel.y / 2].floorIcon; + SearchFloor (rank, icon, cel, bits); + AjustFloor (rank, icon, cel, bits); + if (bits[1 + 1 * 3] == 1) + return false; + + icon = m_decor[cel.x / 2][cel.y / 2].objectIcon; + SearchObject (rank, icon, cel, bits); + AjustObject (rank, icon, cel, bits); + if (bits[1 + 1 * 3] == 1) + return false; + + return true; // pas d'obstacle +} + +// Indique si blupi peut déposer un objet ici. + +bool +CDecor::IsFreeCelDepose (Point cel, Sint32 rank) +{ + Sint32 icon; + + if (!IsFreeCel (cel, rank)) + return false; + + icon = m_decor[cel.x / 2][cel.y / 2].objectIcon; + if ( + icon == 10000 || icon == 10001 || // éclairs entre tours ? + icon == 18) // dalle glissante ? + return false; + + icon = m_decor[cel.x / 2][cel.y / 2].floorIcon; + if (icon == 80) // téléporteur ? + return false; + + return true; +} + +// Indique s'il est possible d'embarquer ici. +// Le point retourné dans "limit" indique jusqu'où il est +// possible de marcher normalement (sans passe muraille). + +bool +CDecor::IsFreeCelEmbarque ( + Point cel, Sint32 rank, Sint32 & action, Point & limit) +{ + bool bOK; + Sint32 channel, icon; + + // Impossible si blupi n'est pas à pied, + // ou s'il s'agit d'un disciple. + if (rank == -1 || m_blupi[rank].vehicule != 0 || m_blupi[rank].perso == 8) + return false; + + // A-t-on cliqué sur un bateau ? + if (cel.x % 2 != 1 || cel.y % 2 != 1) + return false; + GetObject (cel, channel, icon); + if (channel != CHOBJECT || icon != 117) + return false; + + GetFloor (cel, channel, icon); + if (channel == CHFLOOR && icon == 2) + { + m_blupi[rank].vehicule = 1; + bOK = IsFreeCel (GetCel (cel, +1, 0), rank); // libre (en bateau) ? + m_blupi[rank].vehicule = 0; + if (bOK) + { + limit = GetCel (cel, -2, 0); + action = EV_ACTION_BOATDE; + return true; + } + } + + GetFloor (cel, channel, icon); + if (channel == CHFLOOR && icon == 3) + { + m_blupi[rank].vehicule = 1; + bOK = IsFreeCel (GetCel (cel, 0, +1), rank); // libre (en bateau) ? + m_blupi[rank].vehicule = 0; + if (bOK) + { + limit = GetCel (cel, 0, -2); + action = EV_ACTION_BOATDS; + return true; + } + } + + GetFloor (cel, channel, icon); + if (channel == CHFLOOR && icon == 4) + { + m_blupi[rank].vehicule = 1; + bOK = IsFreeCel (GetCel (cel, -1, 0), rank); // libre (en bateau) ? + m_blupi[rank].vehicule = 0; + if (bOK) + { + limit = GetCel (cel, +1, 0); + action = EV_ACTION_BOATDO; + return true; + } + } + + GetFloor (cel, channel, icon); + if (channel == CHFLOOR && icon == 5) + { + m_blupi[rank].vehicule = 1; + bOK = IsFreeCel (GetCel (cel, 0, -1), rank); // libre (en bateau) ? + m_blupi[rank].vehicule = 0; + if (bOK) + { + limit = GetCel (cel, 0, +1); + action = EV_ACTION_BOATDN; + return true; + } + } + + return false; +} + +// Indique s'il est possible de débarquer ici. +// Le point retourné dans "limit" indique jusqu'où il est +// possible de naviguer normalement (sans passe muraille). + +bool +CDecor::IsFreeCelDebarque ( + Point cel, Sint32 rank, Sint32 & action, Point & limit) +{ + bool bOK; + Sint32 channel1, icon1; + Sint32 channel2, icon2; + + // Impossible si blupi n'est pas en bateau. + if (rank == -1 || m_blupi[rank].vehicule != 1) + return false; + + m_blupi[rank].vehicule = 0; + bOK = IsFreeCel (cel, rank); // libre (à pied) ? + m_blupi[rank].vehicule = 1; + if (!bOK) + return false; + + GetFloor (GetCel (cel, +2, 0), channel1, icon1); + GetObject (GetCel (cel, +2, 0), channel2, icon2); + if ( + channel1 == CHFLOOR && icon1 == 2 && // rive ? + channel2 == -1 && icon2 == -1 && // pas de bateau amarré ? + cel.x % 2 == 1 && cel.y % 2 == 1) + { + limit = GetCel (cel, +3, 0); + action = EV_ACTION_BOATAE; + return true; + } + + GetFloor (GetCel (cel, 0, +2), channel1, icon1); + GetObject (GetCel (cel, 0, +2), channel2, icon2); + if ( + channel1 == CHFLOOR && icon1 == 3 && // rive ? + channel2 == -1 && icon2 == -1 && // pas de bateau amarré ? + cel.x % 2 == 1 && cel.y % 2 == 1) + { + limit = GetCel (cel, 0, +3); + action = EV_ACTION_BOATAS; + return true; + } + + GetFloor (GetCel (cel, -2, 0), channel1, icon1); + GetObject (GetCel (cel, -2, 0), channel2, icon2); + if ( + channel1 == CHFLOOR && icon1 == 4 && // rive ? + channel2 == -1 && icon2 == -1 && // pas de bateau amarré ? + cel.x % 2 == 0 && cel.y % 2 == 1) + { + limit = GetCel (cel, -2, 0); + action = EV_ACTION_BOATAO; + return true; + } + + GetFloor (GetCel (cel, 0, -2), channel1, icon1); + GetObject (GetCel (cel, 0, -2), channel2, icon2); + if ( + channel1 == CHFLOOR && icon1 == 5 && // rive ? + channel2 == -1 && icon2 == -1 && // pas de bateau amarré ? + cel.x % 2 == 1 && cel.y % 2 == 0) + { + limit = GetCel (cel, 0, -2); + action = EV_ACTION_BOATAN; + return true; + } + + return false; +} + +// Indique s'il est possible de sauter dans une direction. + +bool +CDecor::IsFreeJump (Point cel, Sint32 direct, Sint32 rank, Sint32 & action) +{ + Point depart, vector; + Sint32 i, icon; + Sint32 bits[3 * 3]; + + // Refuse de sauter si blupi n'est pas à pied ! + if (m_blupi[rank].vehicule != 0) + return false; + + // Refuse de sauter dans les directions se, so, no, ne. + if ((direct / 16) % 2 != 0) + return false; + + // Refuse de sauter si peu d'énergie ou si porte qq chose. + if ( + m_blupi[rank].perso != 0 || m_blupi[rank].energy <= MAXENERGY / 4 || + m_blupi[rank].takeChannel != -1) + return false; + + vector = GetVector (direct); + depart = cel; + + i = 0; + while (true) + { + cel.x += vector.x; + cel.y += vector.y; + + if (i == 4) + break; + if (IsFreeCelFloor (cel, rank)) + break; + i++; + } + if (i == 0) + return false; + + // Départ possible par-rapport aux obstacles ? + icon = m_decor[depart.x / 2][depart.y / 2].objectIcon; + SearchObject (rank, icon, depart, bits); + AjustObject (rank, icon, depart, bits); + if (bits[(1 + vector.x) + (1 + vector.y) * 3] == 1) + return false; + + // Arrivée possible par-rapport aux obstacles ? + icon = m_decor[cel.x / 2][cel.y / 2].objectIcon; + SearchObject (rank, icon, cel, bits); + AjustObject (rank, icon, cel, bits); + if (bits[(1 - vector.x) + (1 - vector.y) * 3] == 1) + return false; + + if (!IsFreeCel (cel, rank) || IsBlupiHere (cel, true)) + return false; + + action = ACTION_JUMP2 + (i - 1); + return true; +} + +// Indique s'il est possible de glisser dans une direction. + +bool +CDecor::IsFreeGlisse (Point cel, Sint32 direct, Sint32 rank, Sint32 & action) +{ + Sint32 channel, icon; + + // Y'a que blupi qui glisse ! + if (m_blupi[rank].perso != 0) + return false; + + GetFloor (GetCel ((cel.x / 2) * 2, (cel.y / 2) * 2), channel, icon); + if (channel != CHFLOOR || icon != 18) // pas dalle glissante ? + return false; + + if (!IsFreeDirect (cel, direct, rank)) + return false; + + action = ACTION_SLIDE; + return true; +} + +// Cherche la meilleure direction pour atteindre un but. +// Retourne -1 si on est déjà sur le but. + +Sint32 +CDecor::DirectSearch (Point cel, Point goal) +{ + Point dir; + Sint32 direct, tan; + + dir.x = goal.x - cel.x; + dir.y = goal.y - cel.y; + + if (dir.x == 0 && dir.y == 0) // but atteint ? + return -1; + +#if 0 + if (dir.x > 0) + { + if (dir.y > 0) + direct = DIRECT_SE; + if (dir.y == 0) + direct = DIRECT_E; + if (dir.y < 0) + direct = DIRECT_NE; + } + + if (dir.x == 0) + { + if (dir.y > 0) + direct = DIRECT_S; + else + direct = DIRECT_N; + } + + if (dir.x < 0) + { + if (dir.y > 0) + direct = DIRECT_SO; + if (dir.y == 0) + direct = DIRECT_O; + if (dir.y < 0) + direct = DIRECT_NO; + } +#endif + + // Cherche le huitième de cadrant correspondant à + // la direction. + // 41 = 100*tan(22.5) + // 241 = 100*tan(67.5) + if (dir.x == 0) + { + if (dir.y > 0) + direct = DIRECT_S; + else + direct = DIRECT_N; + } + else + { + tan = abs (100 * dir.y / dir.x); // calcule la tangente*100 + + if (dir.x > 0) + { + if (dir.y > 0) + { + direct = DIRECT_SE; + if (tan < 41) + direct = DIRECT_E; + if (tan > 241) + direct = DIRECT_S; + } + else + { + direct = DIRECT_NE; + if (tan < 41) + direct = DIRECT_E; + if (tan > 241) + direct = DIRECT_N; + } + } + else + { + if (dir.y > 0) + { + direct = DIRECT_SW; + if (tan < 41) + direct = DIRECT_W; + if (tan > 241) + direct = DIRECT_S; + } + else + { + direct = DIRECT_NW; + if (tan < 41) + direct = DIRECT_W; + if (tan > 241) + direct = DIRECT_N; + } + } + } + + return direct; +} + +// Vide les positions déjà essayées. + +void +CDecor::FlushUsed (Sint32 rank) +{ + m_blupi[rank].nbUsed = 0; + m_blupi[rank].nextRankUsed = 0; +} + +// Ajoute une position déjà été essayée. + +void +CDecor::AddUsedPos (Sint32 rank, Point pos) +{ + Sint32 i, j, old; + + // Un virus est bête. + if (m_blupi[rank].perso == 2) + return; + + // Déjà dans la liste ? + for (i = 0; i < m_blupi[rank].nbUsed; i++) + { + if ( + pos.x == m_blupi[rank].posUsed[i].x && + pos.y == m_blupi[rank].posUsed[i].y) + { + m_blupi[rank].rankUsed[i] = m_blupi[rank].nextRankUsed; + m_blupi[rank].nextRankUsed++; + return; + } + } + + // Si la liste est pleine, remplace le plus vieux point. + if (m_blupi[rank].nbUsed >= MAXUSED) + { + old = 10000; + j = 0; + for (i = 0; i < m_blupi[rank].nbUsed; i++) + { + if (m_blupi[rank].rankUsed[i] < old) + { + old = m_blupi[rank].rankUsed[i]; + j = i; + } + } + m_blupi[rank].posUsed[j] = pos; + m_blupi[rank].rankUsed[j] = m_blupi[rank].nextRankUsed; + m_blupi[rank].nextRankUsed++; + return; + } + + // Ajoute à la suite de la liste. + i = m_blupi[rank].nbUsed; + + m_blupi[rank].posUsed[i] = pos; + m_blupi[rank].rankUsed[i] = m_blupi[rank].nextRankUsed; + m_blupi[rank].nbUsed++; + m_blupi[rank].nextRankUsed++; + return; +} + +// Cherche si une position a déjà été essayée. + +bool +CDecor::IsUsedPos (Sint32 rank, Point pos) +{ + Sint32 i; + + for (i = 0; i < m_blupi[rank].nbUsed; i++) + { + if ( + pos.x == m_blupi[rank].posUsed[i].x && + pos.y == m_blupi[rank].posUsed[i].y) + return true; + } + + return false; +} + +// Cherche la meilleure direction pour atteindre un but. + +bool +CDecor::SearchBestBase ( + Sint32 rank, Sint32 & action, Point & newCel, Sint32 & direct) +{ + Sint32 searchDirect[8] = {0, 1, 7, 2, 6, 5, 3, 4}; + Sint32 tryDirect, workBlupi, i, a; + Point cel, vector; + bool bFree; + + cel = m_blupi[rank].cel; + direct = DirectSearch (cel, m_blupi[rank].goalCel); + + AddUsedPos (rank, cel); + + for (i = 0; i < 8; i++) + { + tryDirect = ((direct / 16 + searchDirect[i]) % 8) * 16; + + vector = GetVector (tryDirect); + + bFree = IsFreeGlisse (cel, tryDirect, rank, action); + + if (!bFree) + { + bFree = IsFreeDirect (cel, tryDirect, rank); + action = ACTION_WALK; + } + + if (!bFree) + bFree = IsFreeJump (cel, tryDirect, rank, action); + + a = GetAmplitude (action); + + // Blupi peut aller sur le lieu de la construction. + if (m_blupi[rank].passCel.x != -1) + { + newCel = m_blupi[rank].passCel; + workBlupi = m_decor[newCel.x / 2][newCel.y / 2].workBlupi; + + if ( + m_blupi[rank].passCel.x / 2 == (cel.x + vector.x * a) / 2 && + m_blupi[rank].passCel.y / 2 == (cel.y + vector.y * a) / 2 && + (workBlupi < 0 || workBlupi == rank)) + bFree = true; + } + + if (bFree) + { + newCel.x = cel.x + vector.x * a; + newCel.y = cel.y + vector.y * a; + + if (!IsUsedPos (rank, newCel)) + { + if (m_blupi[rank].perso == 3) // tracks ? + { + // Le tracks peut aller sur les blupi + // pour les écraser ! + if (IsTracksHere (newCel, false)) + continue; + else + { + AddUsedPos (rank, newCel); + direct = tryDirect; + return true; + } + } + else + { + if (IsBlupiHere (newCel, false)) + { + // Si blupi immobile, comme si obstacle qq. + if (m_blupi[m_blupiHere].goalCel.x == -1) + continue; + newCel = cel; + action = ACTION_STOP; + direct = tryDirect; + return true; + } + else + { + AddUsedPos (rank, newCel); + direct = tryDirect; + return true; + } + } + } + } + } + + return false; +} + +// Cherche la meilleure direction pour atteindre un but. + +bool +CDecor::SearchBestPass (Sint32 rank, Sint32 & action) +{ + Blupi iBlupi; + Sint32 i, j, direct; + Point iCel, lCel = {0}, cel; + + if ( + m_blupi[rank].perso == 0 || // blupi ? + m_blupi[rank].perso == 7 || // électro ? + m_blupi[rank].perso == 8 || // disciple ? + (m_blupi[rank].perso == 4 && // robot ? + m_term.bHachRobot)) // robot sur dalles hachurées ? + { + if (m_blupi[rank].busyDelay > 0) + { + m_blupi[rank].busyDelay--; + if (m_blupi[rank].busyDelay == 0 && m_blupi[rank].busyCount > 0) + m_blupi[rank].busyCount--; + return false; + } + if (CheminCherche (rank, action)) // recherche futée selon DD ... + return true; + else + { + // Si la destination est occupée pendant une répétition, + // il faut attendre à l'infini ! + if ( + m_blupi[rank].repeatLevel != -1 && + IsBlupiHereEx (m_blupi[rank].goalCel, rank, false)) + m_blupi[rank].busyCount++; + m_blupi[rank].busyDelay = Random (8, 12); // délai avant réessai + return false; + } + } + + for (j = 0; j < 7; j++) + { + iBlupi = m_blupi[rank]; // sauvegarde blupi + + // Essaye 7 coups en avance, pour voir. + iCel = m_blupi[rank].cel; + i = 0; + while (true) + { + if (!SearchBestBase (rank, action, cel, direct)) + break; + if (action == ACTION_STOP) // collision avec autre blupi ? + { + if (i == 0) + { + m_blupi[rank] = iBlupi; // restitue blupi + return false; + } + i = 7; // comme si ok pour 7 coups + break; + } + m_blupi[rank].cel = cel; + lCel = cel; + + // Est-on revenu juste à côté de la position + // de départ ? Si oui, simplifie le mouvement. + if ( + i > 1 && abs (m_blupi[rank].cel.x - iCel.x) <= 1 && + abs (m_blupi[rank].cel.y - iCel.y) <= 1) + { + direct = DirectSearch (iCel, cel); + if (IsFreeDirect (iCel, direct, rank)) + { + m_blupi[rank].cel = iCel; + m_blupi[rank].sDirect = direct; + action = ACTION_WALK; + return true; + } + } + + // A-t-on atteint le but ? + if (cel.x == m_blupi[rank].goalCel.x && cel.y == m_blupi[rank].goalCel.y) + { + i = 7; // comme si ok pour 7 coups + break; + } + + i++; + if (i >= 7) + break; + } + + m_blupi[rank] = iBlupi; // restitue blupi + + if (i == 0) + return false; + + if (i == 7) + { + SearchBestBase (rank, action, cel, direct); + m_blupi[rank].sDirect = direct; + return true; + } + + AddUsedPos (rank, lCel); // bloque position ridicule + } + + return false; +} + +// Vérifie si un objet est utilisable pour travailler dessus. +// Le sol doit permettre d'aller aux 4 coins, et il ne doit +// pas y avoir un autre blupi que soi-même. + +bool +CDecor::IsWorkableObject (Point cel, Sint32 rank) +{ + if ( + !IsFreeCelFloor (GetCel (cel, 0, 0), -1) || + !IsFreeCelFloor (GetCel (cel, 1, 0), -1) || + !IsFreeCelFloor (GetCel (cel, 0, 1), -1) || + !IsFreeCelFloor (GetCel (cel, 1, 1), -1)) + return false; + + if ( + IsBlupiHereEx (GetCel (cel, 0, 0), rank, false) || + IsBlupiHereEx (GetCel (cel, 1, 0), rank, false) || + IsBlupiHereEx (GetCel (cel, 0, 1), rank, false) || + IsBlupiHereEx (GetCel (cel, 1, 1), rank, false)) + return false; + + if ( + m_decor[cel.x / 2][cel.y / 2].fire > 0 && + m_decor[cel.x / 2][cel.y / 2].fire < MoveMaxFire ()) + return false; + + return true; +} + +// Cherche un autre objet pour continuer une action +// (comme par exemple abatre des arbres). + +bool +CDecor::SearchOtherObject ( + Sint32 rank, Point initCel, Sint32 action, Sint32 distMax, Sint32 channel, + Sint32 firstIcon1, Sint32 lastIcon1, Sint32 firstIcon2, Sint32 lastIcon2, + Point & foundCel, Sint32 & foundIcon) +{ + Sint32 startx, starty, endx, endy; + Sint32 x, y, xx = 0, yy = 0; + Sint32 dist, min = distMax; + Point cel; + bool bOK; + + if ( + firstIcon1 == 33 && lastIcon1 == 48 && firstIcon2 == 71 && + lastIcon2 == 71) // cherche du fer ? + { + return SearchOtherDrapeau (rank, initCel, distMax, foundCel, foundIcon); + } + + initCel.x = (initCel.x / 2) * 2; + initCel.y = (initCel.y / 2) * 2; + + startx = ((initCel.x - distMax / 2) / 2) * 2; + endx = ((initCel.x + distMax / 2) / 2) * 2; + starty = ((initCel.y - distMax / 2) / 2) * 2; + endy = ((initCel.y + distMax / 2) / 2) * 2; + + if (startx < 0) + startx = 0; + if (endx > MAXCELX) + endx = MAXCELX; + if (starty < 0) + starty = 0; + if (endy > MAXCELY) + endy = MAXCELY; + + if (firstIcon2 == -1 && lastIcon2 == -1) + { + firstIcon2 = 22222; + lastIcon2 = 22222; + } + + for (y = starty; y < endy; y += 2) + { + for (x = startx; x < endx; x += 2) + { + bOK = false; + + if (channel == CHFLOOR) + { + if ( + m_decor[x / 2][y / 2].floorChannel == channel && + ((m_decor[x / 2][y / 2].floorIcon >= firstIcon1 && + m_decor[x / 2][y / 2].floorIcon <= lastIcon1) || + (m_decor[x / 2][y / 2].floorIcon >= firstIcon2 && + m_decor[x / 2][y / 2].floorIcon <= lastIcon2)) && + m_decor[x / 2][y / 2].objectChannel == -1) + bOK = true; + } + else + { + if ( + m_decor[x / 2][y / 2].objectChannel == channel && + ((m_decor[x / 2][y / 2].objectIcon >= firstIcon1 && + m_decor[x / 2][y / 2].objectIcon <= lastIcon1) || + (m_decor[x / 2][y / 2].objectIcon >= firstIcon2 && + m_decor[x / 2][y / 2].objectIcon <= lastIcon2))) + bOK = true; + } + + if (bOK) + { + cel.x = x; + cel.y = y; + if (BlupiIsGoalUsed (cel)) + continue; + + if ( + action == EV_ACTION_ABAT1 || action == EV_ACTION_BUILD1 || + action == EV_ACTION_BUILD2 || action == EV_ACTION_BUILD3 || + action == EV_ACTION_BUILD4 || action == EV_ACTION_BUILD5 || + action == EV_ACTION_BUILD6 || action == EV_ACTION_ROC1 || + action == EV_ACTION_WALL || action == EV_ACTION_BRIDGEE || + action == EV_ACTION_TOWER || action == EV_ACTION_BOATE || + action == EV_ACTION_CULTIVE2 || action == EV_ACTION_FLAG2 || + action == EV_ACTION_DROP) + { + if (!IsWorkableObject (cel, rank)) + continue; + } + + dist = abs (initCel.x - x) + abs (initCel.y - y); + if (dist <= min) + { + min = dist; + xx = x; + yy = y; + } + } + } + } + + if (min == distMax) + return false; + + foundCel.x = xx; + foundCel.y = yy; + + if (channel == CHFLOOR) + foundIcon = m_decor[xx / 2][yy / 2].floorIcon; + else + foundIcon = m_decor[xx / 2][yy / 2].objectIcon; + + return true; +} + +// Cherche un autre sol pouvant contenir du fer, pour y +// planter un drapeau. + +bool +CDecor::SearchOtherDrapeau ( + Sint32 rank, Point initCel, Sint32 distMax, Point & foundCel, + Sint32 & foundIcon) +{ + Sint32 startx, starty, endx, endy, icon; + Sint32 x, y; + Sint32 dist, min = distMax; + Point cel; + + startx = ((initCel.x - distMax / 2) / 2) * 2; + endx = ((initCel.x + distMax / 2) / 2) * 2; + starty = ((initCel.y - distMax / 2) / 2) * 2; + endy = ((initCel.y + distMax / 2) / 2) * 2; + + if (startx < 0) + startx = 0; + if (endx > MAXCELX) + endx = MAXCELX; + if (starty < 0) + starty = 0; + if (endy > MAXCELY) + endy = MAXCELY; + + for (y = starty; y < endy; y += 2) + { + for (x = startx; x < endx; x += 2) + { + icon = m_decor[x / 2][y / 2].floorIcon; + + if ( + m_decor[x / 2][y / 2].objectIcon == -1 && + ((icon >= 33 && icon <= 48) || // terre ? + icon == 71) && + !TestDrapeau (GetCel (x, y))) // pas encore sondé ? + { + cel.x = x; + cel.y = y; + if (BlupiIsGoalUsed (cel)) + continue; + if (!IsWorkableObject (cel, rank)) + continue; + + dist = abs (initCel.x - x) + abs (initCel.y - y); + if (dist <= min) + { + min = dist; + foundCel.x = x; + foundCel.y = y; + foundIcon = icon; + } + } + } + } + + if (min == distMax) + return false; + return true; +} + +// Cherche un autre sol permettant de déposer du bois +// pour construire un bateau. + +bool +CDecor::SearchOtherBateau ( + Sint32 rank, Point initCel, Sint32 distMax, Point & foundCel, + Sint32 & foundIcon) +{ + Sint32 startx, starty, endx, endy; + Sint32 x, y, direct; + Sint32 dist, min = distMax; + + startx = ((initCel.x - distMax / 2) / 2) * 2; + endx = ((initCel.x + distMax / 2) / 2) * 2; + starty = ((initCel.y - distMax / 2) / 2) * 2; + endy = ((initCel.y + distMax / 2) / 2) * 2; + + if (startx < 0) + startx = 0; + if (endx > MAXCELX) + endx = MAXCELX; + if (starty < 0) + starty = 0; + if (endy > MAXCELY) + endy = MAXCELY; + + for (y = starty; y < endy; y += 2) + { + for (x = startx; x < endx; x += 2) + { + if (!IsBuildBateau (GetCel (x, y), direct)) + continue; + + dist = abs (initCel.x - x) + abs (initCel.y - y); + if (dist <= min) + { + min = dist; + foundCel.x = x; + foundCel.y = y; + foundIcon = m_decor[x / 2][y / 2].floorIcon; + } + } + } + + if (min == distMax) + return false; + return true; +} + +// Vérifie si l'objet peut être détruit par l'araignée. + +bool +CDecor::IsSpiderObject (Sint32 icon) +{ + return ( + icon == 60 || // tomates ? + icon == 92 || // poison ? + icon == 93); // piège ? +} + +// Cherche un autre objet pour l'araignée. + +bool +CDecor::SearchSpiderObject ( + Sint32 rank, Point initCel, Sint32 distMax, Point & foundCel, + Sint32 & foundIcon) +{ + Sint32 startx, starty, endx, endy; + Sint32 x, y; + Sint32 dist, min = distMax; + Point cel; + + startx = ((initCel.x - distMax / 2) / 2) * 2; + endx = ((initCel.x + distMax / 2) / 2) * 2; + starty = ((initCel.y - distMax / 2) / 2) * 2; + endy = ((initCel.y + distMax / 2) / 2) * 2; + + if (startx < 0) + startx = 0; + if (endx > MAXCELX) + endx = MAXCELX; + if (starty < 0) + starty = 0; + if (endy > MAXCELY) + endy = MAXCELY; + + for (y = starty; y < endy; y += 2) + { + for (x = startx; x < endx; x += 2) + { + if (IsSpiderObject (m_decor[x / 2][y / 2].objectIcon)) + { + cel.x = x; + cel.y = y; + if (IsBlupiHere (cel, false)) + continue; + + dist = abs (initCel.x - x) + abs (initCel.y - y); + + if ( + m_decor[x / 2][y / 2].objectIcon == 93 && // piège ? + dist > 4) + continue; // si piège loin -> ignore + + if (dist <= min) + { + min = dist; + foundCel.x = x + 1; + foundCel.y = y + 1; // +1 -> sur l'objet + foundIcon = m_decor[x / 2][y / 2].objectIcon; + } + } + } + } + + if (min == distMax) + return false; + + return true; +} + +// Vérifie si l'objet peut être détruit par le tracks. + +bool +CDecor::IsTracksObject (Sint32 icon) +{ + return ( + icon == 36 || // planches ? + icon == 44 || // pierres ? + icon == 60 || // tomates ? + icon == 63 || // oeufs ? + icon == 80 || // bouteille ? + icon == 85 || // dynamite ? + icon == 92 || // poison ? + icon == 93 || // piège ? + icon == 123 || // piège ? + icon == 125 || // mine ? + icon == 127 || // mine ? + (icon >= 81 && icon <= 84) || // fleurs ? + (icon >= 94 && icon <= 95)); // fleurs ? +} + +// Cherche un autre objet pour le tracks. + +bool +CDecor::SearchTracksObject ( + Sint32 rank, Point initCel, Sint32 distMax, Point & foundCel, + Sint32 & foundIcon) +{ + Sint32 startx, starty, endx, endy, icon; + Sint32 x, y; + Sint32 dist, min = distMax; + + startx = ((initCel.x - distMax / 2) / 2) * 2; + endx = ((initCel.x + distMax / 2) / 2) * 2; + starty = ((initCel.y - distMax / 2) / 2) * 2; + endy = ((initCel.y + distMax / 2) / 2) * 2; + + if (startx < 0) + startx = 0; + if (endx > MAXCELX) + endx = MAXCELX; + if (starty < 0) + starty = 0; + if (endy > MAXCELY) + endy = MAXCELY; + + for (y = starty; y < endy; y += 2) + { + for (x = startx; x < endx; x += 2) + { + if (IsTracksObject (m_decor[x / 2][y / 2].objectIcon)) + { + //? cel.x = x; + //? cel.y = y; + //? if ( BlupiIsGoalUsed(cel) ) continue; + //? if ( IsBlupiHere(cel, false) ) continue; + + dist = abs (initCel.x - x) + abs (initCel.y - y); + if (dist <= min) + { + min = dist; + foundCel.x = x + 1; + foundCel.y = y + 1; // +1 -> sur l'objet + foundIcon = m_decor[x / 2][y / 2].objectIcon; + } + } + } + } + + // Le tracks peut écraser blupi. + for (rank = 0; rank < MAXBLUPI; rank++) + { + if ( + m_blupi[rank].bExist && m_blupi[rank].perso == 0 && // blupi ? + m_blupi[rank].vehicule == 0) // à pied ? + { + //? if ( BlupiIsGoalUsed(m_blupi[rank].cel) ) continue; + + x = m_blupi[rank].cel.x; + y = m_blupi[rank].cel.y; + + icon = m_decor[x / 2][y / 2].objectIcon; + if ( + icon == 113 || // maison ? + icon == 28 || icon == 29 || // laboratoire ? + icon == 119 || icon == 120 || // usine ? + icon == 121 || icon == 122) // mine de fer ? + continue; + + dist = abs (initCel.x - x) + abs (initCel.y - y); + if (dist <= min) + { + min = dist; + foundCel.x = x; + foundCel.y = y; + foundIcon = -1; // blupi (pas un objet) ! + } + } + } + + if (min == distMax) + return false; + + return true; +} + +// Vérifie si l'objet peut être détruit par le robot. + +bool +CDecor::IsRobotObject (Sint32 icon) +{ + return ( + icon == 85 || // dynamite ? + icon == 93 || // piège ? + icon == 125 || // mine ? + icon == 127); // mine ? +} + +// Cherche une autre action pour le robot. +// C'est ici qu'est contenue l'IA du robot ! + +bool +CDecor::SearchRobotObject ( + Sint32 rank, Point initCel, Sint32 distMax, Point & foundCel, + Sint32 & foundIcon, Sint32 & foundAction) +{ + Sint32 startx, starty, endx, endy; + Sint32 x, y; + Sint32 dist, maxUsine, min = distMax; + Sint32 nbUsine[10]; + Sint32 nbPerso[10]; + Sint32 i, r, d, dd, icon, index, nb; + + if (m_term.bHachRobot) // robot sur dalles hachurées ? + { + foundAction = EV_ACTION_GO; + return SearchOtherObject ( + rank, initCel, EV_ACTION_GO, 200, CHFLOOR, 17, 17, -1, -1, foundCel, + foundIcon); + } + + initCel.x = (initCel.x / 2) * 2; + initCel.y = (initCel.y / 2) * 2; // bâtiments très espacés ! + + startx = ((initCel.x - distMax / 2) / 2) * 2; + endx = ((initCel.x + distMax / 2) / 2) * 2; + starty = ((initCel.y - distMax / 2) / 2) * 2; + endy = ((initCel.y + distMax / 2) / 2) * 2; + + for (i = 0; i < 10; i++) + nbUsine[i] = 0; + + if (startx < 0) + startx = 0; + if (endx > MAXCELX) + endx = MAXCELX; + if (starty < 0) + starty = 0; + if (endy > MAXCELY) + endy = MAXCELY; + + for (y = starty; y < endy; y += 2) + { + for (x = startx; x < endx; x += 2) + { + icon = m_decor[x / 2][y / 2].objectIcon; + + if (icon == 99) + nbUsine[0]++; // recharge ? + if (icon == 104) + nbUsine[1]++; // usine tracks ? + if (icon == 100) + nbUsine[2]++; // usine araignée ? + if (icon == 102) + nbUsine[3]++; // usine virus ? + if (icon == 115) + nbUsine[4]++; // usine bombe ? + if (icon == 17) + nbUsine[5]++; // usine électro ? + + dist = abs (initCel.x - x) + abs (initCel.y - y); + + if ( + IsRobotObject (icon) && // piège/dynamite ? + dist <= 4) // très proche ? + { + if (dist <= min) + { + min = dist; + foundCel.x = x + 1; + foundCel.y = y + 1; // +1 -> sur l'objet + foundIcon = m_decor[x / 2][y / 2].objectIcon; + } + } + } + } + + if (min < distMax) + { + foundAction = -1; // robot passe tout prèt d'un piège/dynamite + return true; + } + + // Cherche l'usine la moins construite. + min = 999; + maxUsine = 0; + index = 0; + for (i = 0; i < 6; i++) + { + if (nbUsine[i] < min) + { + min = nbUsine[i]; + index = i; + } + if (nbUsine[i] > maxUsine) + maxUsine = nbUsine[i]; + } + + //? if ( nbUsine[0] > 0 && // sation de recharge existe ? + //? m_blupi[rank].energy <= MAXENERGY/2 ) // peu de forces ? + //? { + //? index = 0; // station de recharge + //? goto search; + //? } + + if (min == 0) // encore une usine à construire ? + { + // Libre juste ici ? + if (IsUsineBuild (rank, initCel)) + { + foundCel = initCel; + build: + if (index == 0) + foundAction = EV_ACTION_R_BUILD1; // recharge + if (index == 1) + foundAction = EV_ACTION_R_BUILD4; // tracks + if (index == 2) + foundAction = EV_ACTION_R_BUILD2; // araignée + if (index == 3) + foundAction = EV_ACTION_R_BUILD3; // virus + if (index == 4) + foundAction = EV_ACTION_R_BUILD5; // bombe + if (index == 5) + foundAction = EV_ACTION_R_BUILD6; // électro + return true; + } + // Cherche un emplacement libre. + for (d = 1; d < distMax / 6; d++) + { + x = initCel.x + d * 6; + y = initCel.y - d * 6; + for (i = 0; i < 4; i++) // 4 directions + { + for (dd = 0; dd <= d; dd++) + { + if (i == 0) + x -= 6; // à gauche + if (i == 1) + y += 6; // descend + if (i == 2) + x += 6; // à droite + if (i == 3) + y -= 6; // monte + + if (IsUsineBuild (rank, GetCel (x, y))) + { + foundCel.x = x; + foundCel.y = y; + goto build; + } + } + } + } + } + + // Cherche l'ennemi le moins répandu. + for (i = 0; i < 10; i++) + nbPerso[i] = 0; + nb = 0; + for (r = 0; r < MAXBLUPI; r++) + { + if (m_blupi[r].bExist) + { + nb++; + if (m_blupi[r].perso == 3) // tracks ? + nbPerso[0] += 1; + if (m_blupi[r].perso == 1) // araignée ? + nbPerso[1] += 1; + if (m_blupi[r].perso == 2) // virus ? + nbPerso[2] += 1; + if (m_blupi[r].perso == 5) // bombe ? + nbPerso[3] += 2; + if (m_blupi[r].perso == 7) // électro ? + nbPerso[4] += 2; + } + } + if (nb > MAXBLUPI - 10) + return false; // rien si trop peuplé ! + // Cherche l'ennemi le moins répandu. + min = 999; + index = 0; + for (i = 0; i < 5; i++) + { + if (nbPerso[i] < min && nbUsine[i + 1] != 0) // usine correspondante existe + // ? + { + min = nbPerso[i]; + index = i + 1; + } + } + if (m_blupi[rank].energy <= MAXENERGY / 2) // peu de forces ? + { + index = 0; // station de recharge + } + if (m_skill >= 1) + maxUsine *= 2; // 2 ennemis par batiment + if (min >= maxUsine) // assez peuplé ? + { + index = 0; // station de recharge + } + + // Cherche l'usine pour fabriquer l'ennemi le moins rédandu. + //? search: + min = distMax; + for (y = starty; y < endy; y += 2) + { + for (x = startx; x < endx; x += 2) + { + icon = m_decor[x / 2][y / 2].objectIcon; + + if ( + (index == 0 && icon == 99) || // recharge ? + (index == 1 && icon == 104) || // tracks ? + (index == 2 && icon == 100) || // araignée ? + (index == 3 && icon == 102) || // virus ? + (index == 4 && icon == 115) || // bombe ? + (index == 5 && icon == 17)) // électro ? + { + if (IsUsineFree (rank, GetCel (x, y))) + { + dist = abs (initCel.x - x) + abs (initCel.y - y); + if (dist <= min) + { + min = dist; + foundCel.x = x; + foundCel.y = y; // dans l'usine + foundIcon = icon; + } + } + } + } + } + if (min < distMax) + { + if (index == 0) + foundAction = EV_ACTION_R_MAKE1; // recharge + if (index == 1) + foundAction = EV_ACTION_R_MAKE4; // tracks + if (index == 2) + foundAction = EV_ACTION_R_MAKE2; // araignée + if (index == 3) + foundAction = EV_ACTION_R_MAKE3; // virus + if (index == 4) + foundAction = EV_ACTION_R_MAKE5; // bombe + if (index == 5) + foundAction = EV_ACTION_R_MAKE6; // électro + return true; + } + + // Cherche l'usine la plus proche. + min = distMax; + for (y = starty; y < endy; y += 2) + { + for (x = startx; x < endx; x += 2) + { + icon = m_decor[x / 2][y / 2].objectIcon; + + if ( + (icon == 100 && nbPerso[1] <= maxUsine) || // araignée ? + (icon == 102 && nbPerso[2] <= maxUsine) || // virus ? + (icon == 104 && nbPerso[0] <= maxUsine) || // tracks ? + (icon == 115 && nbPerso[3] <= maxUsine) || // bombe ? + (icon == 17 && nbPerso[4] <= maxUsine)) // électro ? + { + if (IsUsineFree (rank, GetCel (x, y))) + { + dist = abs (initCel.x - x) + abs (initCel.y - y); + if (dist <= min) + { + min = dist; + foundCel.x = x; + foundCel.y = y; // dans l'usine + foundIcon = icon; + } + } + } + } + } + if (min < distMax) + { + if (foundIcon == 100) + foundAction = EV_ACTION_R_MAKE2; // araignée + if (foundIcon == 102) + foundAction = EV_ACTION_R_MAKE3; // virus + if (foundIcon == 104) + foundAction = EV_ACTION_R_MAKE4; // tracks + if (foundIcon == 115) + foundAction = EV_ACTION_R_MAKE5; // bombe + if (foundIcon == 17) + foundAction = EV_ACTION_R_MAKE6; // électro + return true; + } + + return false; +} + +// Teste si un emplacement est ok pour bâtir une usine. + +bool +CDecor::IsUsineBuild (Sint32 rank, Point cel) +{ + Sint32 icon, channel; + Sint32 x, y; + + // Pas sur les dalles hachurées ! + GetFloor (cel, channel, icon); + if (channel == CHFLOOR && (icon < 65 || icon > 67)) + return false; + + for (x = -1; x < 3; x++) + { + for (y = -1; y < 3; y++) + { + if ( + !IsFreeCel (GetCel (cel, x, y), rank) || + IsBlupiHereEx (GetCel (cel, x, y), rank, false)) + return false; + } + } + + return true; +} + +// Teste s'il est possible d'entrer dans une usine. +// L'usine doit être libre devant (lieu de stationnement +// pour l'ennemi qui sera construit). + +bool +CDecor::IsUsineFree (Sint32 rank, Point cel) +{ + Sint32 channel, icon; + + GetObject (cel, channel, icon); + + if (channel == CHOBJECT && icon == 115) // usine à bombes ? + { + return ( + !IsBlupiHereEx (GetCel (cel, 0, 1), rank, false) && + !IsBlupiHereEx (GetCel (cel, 1, 1), rank, false) && + !IsBlupiHereEx (GetCel (cel, 2, 1), rank, false) && + !IsBlupiHereEx (GetCel (cel, 3, 1), rank, false)); + } + + return ( + !IsBlupiHereEx (GetCel (cel, 0, 1), rank, false) && + !IsBlupiHereEx (GetCel (cel, 1, 1), rank, false) && + !IsBlupiHereEx (GetCel (cel, 2, 0), rank, false) && + !IsBlupiHereEx (GetCel (cel, 2, 1), rank, false) && + (!IsBlupiHereEx (GetCel (cel, 3, 0), rank, false) || + !IsBlupiHereEx (GetCel (cel, 3, 1), rank, false))); +} + +// Vérifie si l'objet peut être détruit par une bombe. + +bool +CDecor::IsBombeObject (Sint32 icon) +{ + return ( + icon == 36 || // planches ? + icon == 61 || // cabane ? + icon == 121 || icon == 122 || // mine de fer ? + (icon >= 65 && icon <= 71) || // palissade ? + icon == 93 || // piège ? + icon == 117); // bateau ? +} + +// Cherche un autre objet pour une bombe. + +bool +CDecor::SearchBombeObject ( + Sint32 rank, Point initCel, Sint32 distMax, Point & foundCel, + Sint32 & foundIcon) +{ + Sint32 startx, starty, endx, endy; + Sint32 x, y; + Sint32 dist, min = distMax; + Point cel; + + startx = ((initCel.x - distMax / 2) / 2) * 2; + endx = ((initCel.x + distMax / 2) / 2) * 2; + starty = ((initCel.y - distMax / 2) / 2) * 2; + endy = ((initCel.y + distMax / 2) / 2) * 2; + + if (startx < 0) + startx = 0; + if (endx > MAXCELX) + endx = MAXCELX; + if (starty < 0) + starty = 0; + if (endy > MAXCELY) + endy = MAXCELY; + + for (y = starty; y < endy; y += 2) + { + for (x = startx; x < endx; x += 2) + { + if (IsBombeObject (m_decor[x / 2][y / 2].objectIcon)) + { + cel.x = x; + cel.y = y; + if (IsBlupiHere (cel, false)) + continue; + + dist = abs (initCel.x - x) + abs (initCel.y - y); + + if ( + m_decor[x / 2][y / 2].objectIcon == 93 && // piège ? + dist > 8) + continue; // si piège loin -> ignore + + if (dist <= min) + { + min = dist; + foundCel.x = x + 1; + foundCel.y = y + 1; // +1 -> sur l'objet + foundIcon = m_decor[x / 2][y / 2].objectIcon; + } + } + } + } + + if (min == distMax) + return false; + + return true; +} + +// Cherche un autre objet pour un électro. + +bool +CDecor::SearchElectroObject ( + Sint32 rank, Point initCel, Sint32 distMax, Point & foundCel, + Sint32 & foundIcon) +{ + Sint32 startx, starty, endx, endy; + Sint32 x, y, i, d, dd, r; + Sint32 dist, min = distMax; + Point cel; + + startx = ((initCel.x - 10 / 2) / 2) * 2; + endx = ((initCel.x + 10 / 2) / 2) * 2; + starty = ((initCel.y - 10 / 2) / 2) * 2; + endy = ((initCel.y + 10 / 2) / 2) * 2; + + if (startx < 0) + startx = 0; + if (endx > MAXCELX) + endx = MAXCELX; + if (starty < 0) + starty = 0; + if (endy > MAXCELY) + endy = MAXCELY; + + for (y = starty; y < endy; y += 2) + { + for (x = startx; x < endx; x += 2) + { + if (m_decor[x / 2][y / 2].objectIcon == 93) // piège ? + { + cel.x = x; + cel.y = y; + if (IsBlupiHere (cel, false)) + continue; + + dist = abs (initCel.x - x) + abs (initCel.y - y); + + if (dist <= 4) + { + min = dist; + foundCel.x = x + 1; + foundCel.y = y + 1; // +1 -> sur l'objet + foundIcon = m_decor[x / 2][y / 2].objectIcon; + } + } + } + } + if (min <= 4) + return true; + + min = distMax; + for (r = 0; r < MAXBLUPI; r++) + { + if ( + m_blupi[r].bExist && m_blupi[r].perso == 0 && // blupi ? + m_blupi[r].goalAction != EV_ACTION_ELECTRO) + { + //? if ( BlupiIsGoalUsed(m_blupi[r].cel) ) continue; + + x = m_blupi[r].cel.x; + y = m_blupi[r].cel.y; + dist = abs (initCel.x - x) + abs (initCel.y - y); + if (dist <= distMax / 2 && dist <= min) + { + min = dist; + foundCel.x = x; + foundCel.y = y; + foundIcon = -1; // blupi (pas un objet) ! + } + } + } + if (min == distMax) + return false; + + // Cherche un emplacement libre. + for (d = 1; d < distMax / 2; d++) + { + x = foundCel.x + d; + y = foundCel.y - d; + for (i = 0; i < 4; i++) // 4 directions + { + for (dd = 0; dd <= d; dd++) + { + if (i == 0) + x -= 1; // à gauche + if (i == 1) + y += 1; // descend + if (i == 2) + x += 1; // à droite + if (i == 3) + y -= 1; // monte + + if ( + IsFreeCel (GetCel (x, y), rank) && + !IsBlupiHereEx (GetCel (x, y), rank, false)) + { + foundCel.x = x; + foundCel.y = y; + return true; + } + } + } + } + + return false; +} + +// Teste si une position est très proche du feu. +// Si oui, retourne true. + +bool +CDecor::IsFireCel (Point cel) +{ + Sint32 x, y; + Point test; + + cel.x = (cel.x / 2) * 2; + cel.y = (cel.y / 2) * 2; + + for (x = -2; x < 3; x += 2) + { + for (y = -2; y < 3; y += 2) + { + test.x = cel.x + x; + test.y = cel.y + y; + + if (!IsValid (test)) + continue; + + if ( + m_decor[test.x / 2][test.y / 2].fire > 0 && + m_decor[test.x / 2][test.y / 2].fire < MoveMaxFire ()) + return true; + } + } + + return false; +} + +// Teste si une position est très proche d'un virus. +// Si oui, retourne true. + +bool +CDecor::IsVirusCel (Point cel) +{ + Sint32 rank; + + for (rank = 0; rank < MAXBLUPI; rank++) + { + if (m_blupi[rank].bExist && m_blupi[rank].perso == 2) // virus ? + { + if ( + cel.x >= m_blupi[rank].cel.x - 1 && cel.x <= m_blupi[rank].cel.x + 1 && + cel.y >= m_blupi[rank].cel.y - 1 && cel.y <= m_blupi[rank].cel.y + 1) + return true; + } + } + + return false; +} + +// Regarde s'il est possible de construire un pont à partir +// d'une cellule donnée (cel). +// Retourne 0 si c'est possible, ou une erreur autrement ! + +Errors +CDecor::IsBuildPont (Point & cel, Sint32 & iconBuild) +{ + Point vector, test; + Sint32 i, channel, icon, p1, p2, p3, r1, r2, nb, rest; + Errors error = Errors::MISC; + + for (i = 0; i < 4; i++) + { + vector.x = 0; + vector.y = 0; + + GetFloor (GetCel (cel, +2, 0), channel, icon); + if (i == 0 && channel == CHFLOOR && (icon == 2 || icon == 59)) // rivage ? + { + vector.x = +1; + vector.y = 0; + p1 = 59; + p2 = 60; + p3 = 61; + r1 = 2; + r2 = 4; + } + + GetFloor (GetCel (cel, -2, 0), channel, icon); + if (i == 1 && channel == CHFLOOR && (icon == 4 || icon == 61)) // rivage ? + { + vector.x = -1; + vector.y = 0; + p1 = 61; + p2 = 60; + p3 = 59; + r1 = 4; + r2 = 2; + } + + GetFloor (GetCel (cel, 0, +2), channel, icon); + if (i == 2 && channel == CHFLOOR && (icon == 3 || icon == 62)) // rivage ? + { + vector.x = 0; + vector.y = +1; + p1 = 62; + p2 = 63; + p3 = 64; + r1 = 3; + r2 = 5; + } + + GetFloor (GetCel (cel, 0, -2), channel, icon); + if (i == 3 && channel == CHFLOOR && (icon == 5 || icon == 64)) // rivage ? + { + vector.x = 0; + vector.y = -1; + p1 = 64; + p2 = 63; + p3 = 62; + r1 = 5; + r2 = 3; + } + + if (vector.x == 0 && vector.y == 0) + continue; + + // Avance tant que le pont existe. + test = cel; + nb = 0; + do + { + test.x += vector.x * 2; + test.y += vector.y * 2; + if (test.x < 0 || test.x >= MAXCELX || test.y < 0 || test.y >= MAXCELY) + break; + + if (!GetFloor (test, channel, icon)) + continue; + nb++; + } while (icon == p1 || icon == p2); + test.x -= vector.x * 2; + test.y -= vector.y * 2; + + if (icon == p3) + { + error = Errors::PONTTERM; + continue; + } + + if (nb == 1) + iconBuild = p1; + else + iconBuild = p2; + + // Avance jusqu'à la rive opposée. + rest = 0; + do + { + test.x += vector.x * 2; + test.y += vector.y * 2; + if (test.x < 0 || test.x >= MAXCELX || test.y < 0 || test.y >= MAXCELY) + break; + + if (!GetFloor (test, channel, icon)) + continue; + rest++; + } while (icon == r1 || icon == 14); + + if (icon == r2 && rest == 1) + iconBuild = p3; + + if (icon != r2 && icon != p2 && icon != p3) + { + error = Errors::PONTOP; + continue; + } + + cel.x += vector.x * 2 * nb; + cel.y += vector.y * 2 * nb; + + return Errors::NONE; // ok + } + + return error; +} + +// Regarde s'il est possible de construire un bateau à partir +// d'une cellule donnée (cel). + +bool +CDecor::IsBuildBateau (Point cel, Sint32 & direct) +{ + Sint32 fChannel, fIcon; + Sint32 oChannel, oIcon; + + GetFloor (GetCel (cel, +2, 0), fChannel, fIcon); + GetObject (GetCel (cel, +2, 0), oChannel, oIcon); + if ( + fChannel == CHFLOOR && fIcon == 2 && // rivage ? + oChannel == -1 && oIcon == -1) + { + direct = DIRECT_E; + return true; + } + + GetFloor (GetCel (cel, -2, 0), fChannel, fIcon); + GetObject (GetCel (cel, -2, 0), oChannel, oIcon); + if ( + fChannel == CHFLOOR && fIcon == 4 && // rivage ? + oChannel == -1 && oIcon == -1) + { + direct = DIRECT_W; + return true; + } + + GetFloor (GetCel (cel, 0, +2), fChannel, fIcon); + GetObject (GetCel (cel, 0, +2), oChannel, oIcon); + if ( + fChannel == CHFLOOR && fIcon == 3 && // rivage ? + oChannel == -1 && oIcon == -1) + { + direct = DIRECT_S; + return true; + } + + GetFloor (GetCel (cel, 0, -2), fChannel, fIcon); + GetObject (GetCel (cel, 0, -2), oChannel, oIcon); + if ( + fChannel == CHFLOOR && fIcon == 5 && // rivage ? + oChannel == -1 && oIcon == -1) + { + direct = DIRECT_N; + return true; + } + + direct = -1; + return false; +} + +// Vide toutes les positions visitées. + +void +CDecor::InitDrapeau () +{ + Sint32 i; + + for (i = 0; i < MAXLASTDRAPEAU; i++) + { + m_lastDrapeau[i].x = -1; + m_lastDrapeau[i].y = -1; + } +} + +// Mémorise une cellule visitée (ne contenant pas de fer). + +void +CDecor::AddDrapeau (Point cel) +{ + Sint32 i; + + if (TestDrapeau (cel)) + return; // déjà dans la liste + + for (i = MAXLASTDRAPEAU - 1; i > 0; i--) + m_lastDrapeau[i] = m_lastDrapeau[i - 1]; + + m_lastDrapeau[0] = cel; +} + +// Supprime une cellule visitée (ne contenant pas de fer). + +void +CDecor::SubDrapeau (Point cel) +{ + Sint32 i; + + for (i = 0; i < MAXLASTDRAPEAU; i++) + { + if (cel.x == m_lastDrapeau[i].x && cel.y == m_lastDrapeau[i].y) + { + m_lastDrapeau[i].x = -1; + m_lastDrapeau[i].y = -1; + } + } +} + +// Teste si une cellule a déjà été visitée. + +bool +CDecor::TestDrapeau (Point cel) +{ + Sint32 i; + + for (i = 0; i < MAXLASTDRAPEAU; i++) + { + if (cel.x == m_lastDrapeau[i].x && cel.y == m_lastDrapeau[i].y) + return true; + } + + return false; +} diff --git a/src/path.cxx b/src/path.cxx new file mode 100644 index 0000000..9a762b7 --- /dev/null +++ b/src/path.cxx @@ -0,0 +1,390 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997 Daniel Roux, EPSITEC SA & Denis Dumoulin + * Copyright (C) 2017 Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "action.h" +#include "decor.h" +#include "fifo.h" + +// Mémorise toutes les positions des blupi. + +void +CDecor::CheminMemPos (Sint32 exRank) +{ + Sint32 rank, index; + + m_cheminNbPos = 0; + index = 0; + for (rank = 0; rank < MAXBLUPI; rank++) + { + if ( + m_blupi[rank].bExist && + m_blupi[rank].perso != 6 && // pas le détonnateur de mine + rank != exRank) + { + m_cheminPos[index] = m_blupi[rank].cel; + m_cheminRank[index] = rank; + m_cheminNbPos++; + index++; + + if ( + m_blupi[rank].destCel.x != m_blupi[rank].cel.x || + m_blupi[rank].destCel.y != m_blupi[rank].cel.y) + { + m_cheminPos[index] = m_blupi[rank].destCel; + m_cheminRank[index] = rank; + m_cheminNbPos++; + index++; + } + } + } +} + +// Teste si une positiion est occupée par un blupi. + +bool +CDecor::CheminTestPos (Point pos, Sint32 & rank) +{ + Sint32 i; + + for (i = 0; i < m_cheminNbPos; i++) + { + if (pos.x == m_cheminPos[i].x && pos.y == m_cheminPos[i].y) + { + rank = m_cheminRank[i]; + return true; + } + } + + return false; +} + +// une fois le but trouvé, reprend en arrière +// à la recherche du chemin le plus court + +// retourne la direction à prendre +Sint32 +CDecor::CheminARebours (Sint32 rank) +{ + Sint32 pos, rebours, last, dir, set; + Point v; + + pos = m_blupi[rank].goalCel.y * MAXCELX + m_blupi[rank].goalCel.x; + + rebours = m_cheminWork[pos]; + + if (rebours == 0) + return -1; + + while (true) + { + bis: + for (set = 0; set < 2; set++) + { + for (dir = set; dir < 8; dir += 2) + { + v = GetVector (dir * 16); + last = pos + v.y * MAXCELX + v.x; + + if (m_cheminWork[last] > 0 && m_cheminWork[last] < rebours) + { + pos = last; + rebours = m_cheminWork[pos]; + if (rebours == 1) + return (dir >= 4) ? dir - 4 : dir + 4; + goto bis; // interrompt le for... + } + } + } + + // ne devrait jamais arriver ! + return -1; + } +} + +// troisième méthode de recherche +// semblable à la précédente, +// mais les points à explorer sont classés selon leur distance à la cible + +void +CDecor::CheminFillTerrain (Sint32 rank) +{ + Sint32 pos, last, dest, dist; + Sint32 step, dir, cout, action, max, next, ampli; + Sint32 dx, dy; + Sint32 but = 1000; + + if ( + m_blupi[rank].cel.x == m_blupi[rank].goalCel.x && + m_blupi[rank].cel.y == m_blupi[rank].goalCel.y) + return; + + pos = m_blupi[rank].cel.y * MAXCELX + m_blupi[rank].cel.x; + dest = m_blupi[rank].goalCel.y * MAXCELX + m_blupi[rank].goalCel.x; + + CPileTriee fifo (2 * MAXCELX + 2 * MAXCELY); // les variantes possibles + + fifo.put (pos, 0); // position de départ + m_cheminWork[pos] = 1; // première position + + // répète jusqu'à trouvé ou plus de possibilités + max = 500; + while (max-- > 0) + { + // reprend une variante de chemin + pos = fifo.get (); + if (pos < 0) + break; + + step = m_cheminWork[pos]; + + // on est arrivé au but ? + //? if ( pos == dest ) return; + if (pos == dest) + { + but = step; // hélas trop lent ! + max = 50; + } + + // est-ce vraiment trop loin ? + if (step > 200) + return; + + // marque les cases autour du point + if (step < but) + for (dir = 0; dir < 8; dir++) + { + if (!CheminTestDirection (rank, pos, dir, next, ampli, cout, action)) + continue; + + last = pos + ampli * next; + if (last < 0 || last >= MAXCELX * MAXCELY) + continue; + + if (m_cheminWork[last] != 0 && m_cheminWork[last] <= step + cout) + continue; + + // marque les cases sautées + for (Sint32 i = 1; i < ampli; i++) + m_cheminWork[pos + i * next] = step + cout - ampli + i; + + m_cheminWork[last] = step + cout; + + dx = m_blupi[rank].goalCel.x - last % MAXCELX; + dy = m_blupi[rank].goalCel.y - last / MAXCELX; + + dist = (Sint32) (dy * dy) + (Sint32) (dx * dx); + fifo.put (last, dist); + } + } +} + +// routine déterninant si une direction est possible +// retourne l'incrément pour passer à la nouvelle case +// et le "prix à payer" pour aller dans cette direction +// coût doit être déterminé en sortie + +bool +CDecor::CheminTestDirection ( + Sint32 rank, Sint32 pos, Sint32 dir, Sint32 & next, Sint32 & ampli, + Sint32 & cout, Sint32 & action) +{ + Point cel, vector, newCel; + bool bFree; + Sint32 tryDirect, workBlupi, rankHere; + + cel.x = pos % MAXCELX; + cel.y = pos / MAXCELX; + + tryDirect = dir * 16; + vector = GetVector (tryDirect); + + // Peut-on glisser dans cette direction ? + bFree = IsFreeGlisse (cel, tryDirect, rank, action); + cout = 5; // coût élevé + + if (!bFree) + { + // Peut-on marcher normalement ? + bFree = IsFreeDirect (cel, tryDirect, rank); + action = ACTION_WALK; + cout = 1; // coût minimal + } + + if (!bFree) + { + // Peut-on sauter ? + bFree = IsFreeJump (cel, tryDirect, rank, action); + cout = 3; // coût élevé + } + + ampli = GetAmplitude (action); // a <- amplitude (1..5) + cout *= ampli; // coût plus élevé si grande amplitude + + // Blupi peut aller sur le lieu de la construction. + if (!bFree && m_blupi[rank].passCel.x != -1) + { + newCel = m_blupi[rank].passCel; + workBlupi = m_decor[newCel.x / 2][newCel.y / 2].workBlupi; + + if ( + m_blupi[rank].passCel.x / 2 == (cel.x + vector.x * ampli) / 2 && + m_blupi[rank].passCel.y / 2 == (cel.y + vector.y * ampli) / 2 && + (workBlupi < 0 || workBlupi == rank)) + { + bFree = true; + cout = 1; + } + } + + if (bFree) // chemin libre (sans tenir compte des perso) ? + { + newCel.x = cel.x + vector.x * ampli; + newCel.y = cel.y + vector.y * ampli; // newCel <- arrivée suposée + + if (m_blupi[rank].perso == 3) // tracks ? + { + // Le tracks peut aller sur les blupi + // pour les écraser ! + if (IsTracksHere (newCel, false)) // autre perso ici ? + return false; + } + else + { + //? if ( IsBlupiHere(newCel, false) ) // autre perso ici ? + if (CheminTestPos (newCel, rankHere)) // autre perso ici ? + { + // Si blupi immobile, comme si obstacle qq. + //? if ( m_blupi[m_blupiHere].goalCel.x == -1 ) return + // false; + if (m_blupi[rankHere].goalCel.x == -1) + return false; + + // Si blupi mobile, possible mais coût élevé. + cout = 20; + } + } + next = vector.y * MAXCELX + vector.x; + return true; + } + + return false; +} + +// Retourne true si on a assigné une nouvelle direction à blupi. + +bool +CDecor::CheminCherche (Sint32 rank, Sint32 & action) +{ + Sint32 cout; // prix pour aller dans une direction + Sint32 pos, dir, next, ampli; + + // Déjà à destination ? + if ( + m_blupi[rank].cel.x == m_blupi[rank].goalCel.x && + m_blupi[rank].cel.y == m_blupi[rank].goalCel.y) + return false; + + // Destination occupée ? + if (IsBlupiHereEx (m_blupi[rank].goalCel, rank, false)) + return false; + + memset (m_cheminWork, 0, (Uint8) MAXCELX * (Uint8) MAXCELY); + CheminMemPos (rank); + + // fait un remplissage du map de travail + // autour du point de départ + CheminFillTerrain (rank); + + // cherche le chemin à partir de la destination + dir = CheminARebours (rank); + if (dir < 0) + return false; + + pos = m_blupi[rank].cel.y * MAXCELX + m_blupi[rank].cel.x; + if ( + CheminTestDirection (rank, pos, dir, next, ampli, cout, action) && + cout < 20) + { + m_blupi[rank].sDirect = 16 * dir; + return true; + } + + // ne devrait jamais arriver ! + return false; +} + +// Teste s'il est possible de se rendre à un endroit donné. + +bool +CDecor::IsCheminFree (Sint32 rank, Point dest, Sint32 button) +{ + Sint32 action, sDirect; + Point goalCel, passCel, limit; + bool bOK; + + if (button == BUTTON_STOP) + return true; + + goalCel = m_blupi[rank].goalCel; + passCel = m_blupi[rank].passCel; + sDirect = m_blupi[rank].sDirect; + + if (IsFreeCelEmbarque (dest, rank, action, limit)) + dest = limit; + if (IsFreeCelDebarque (dest, rank, action, limit)) + dest = limit; + if ( + button == BUTTON_GO && + m_decor[dest.x / 2][dest.y / 2].objectChannel == CHOBJECT && + (m_decor[dest.x / 2][dest.y / 2].objectIcon == 118 || // jeep ? + m_decor[dest.x / 2][dest.y / 2].objectIcon == 16) && // armure ? + dest.x % 2 == 1 && + dest.y % 2 == 1) + { + dest.y--; // va à côté jeep/armure + } + if ( + button == BUTTON_GO && + m_decor[dest.x / 2][dest.y / 2].objectChannel == CHOBJECT && + m_decor[dest.x / 2][dest.y / 2].objectIcon == 113) // maison ? + { + dest.x = (dest.x / 2) * 2 + 1; + dest.y = (dest.y / 2) * 2 + 1; // sous la porte + } + + if (m_blupi[rank].cel.x == dest.x && m_blupi[rank].cel.y == dest.y) + return true; + + m_blupi[rank].goalCel = dest; + if ( + m_decor[dest.x / 2][dest.y / 2].objectChannel == CHOBJECT && + button != BUTTON_GO) + { + m_blupi[rank].passCel = dest; // si arbres/fleurs/bateau/etc. + } + + bOK = CheminCherche (rank, action); + + m_blupi[rank].goalCel = goalCel; + m_blupi[rank].passCel = passCel; + m_blupi[rank].sDirect = sDirect; + + return bOK; +} diff --git a/src/pixmap.cxx b/src/pixmap.cxx new file mode 100644 index 0000000..de797b8 --- /dev/null +++ b/src/pixmap.cxx @@ -0,0 +1,1061 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2019, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include +#include +#include + +#ifdef _WIN32 +#include +#define access _access +#else /* _WIN32 */ +#include +#endif /* !_WIN32 */ + +#include + +#include "blupi.h" +#include "def.h" +#include "event.h" +#include "misc.h" +#include "pixmap.h" + +///////////////////////////////////////////////////////////////////////////// + +// Constructeur. + +CPixmap::CPixmap (CEvent * event) +{ + Sint32 i; + + m_bDebug = true; + m_bPalette = true; + + m_mouseSprite = SPRITE_WAIT; + m_bBackDisplayed = false; + + m_lpSDLBlupi = nullptr; + + for (i = 0; i < MAXCURSORS; i++) + m_lpSDLCursors[i] = nullptr; + + m_lpCurrentCursor = nullptr; + this->mainTexture = nullptr; + this->event = event; +} + +// Destructeur. + +CPixmap::~CPixmap () +{ + unsigned int i; + + for (i = 0; i < countof (m_lpSDLCursors); i++) + { + if (m_lpSDLCursors[i]) + { + SDL_FreeCursor (m_lpSDLCursors[i]); + m_lpSDLCursors[i] = nullptr; + } + } + + for (auto tex : m_SDLTextureInfo) + { + if (tex.second.texture) + SDL_DestroyTexture (tex.second.texture); + if (tex.second.texMask) + SDL_DestroyTexture (tex.second.texMask); + } + + if (m_lpSDLBlupi) + SDL_FreeSurface (m_lpSDLBlupi); + + if (this->mainTexture) + SDL_DestroyTexture (this->mainTexture); +} + +// Cr�e l'objet DirectDraw principal. +// Retourne false en cas d'erreur. + +bool +CPixmap::Create (Point dim) +{ + m_dim = dim; + + m_clipRect.left = 0; + m_clipRect.top = 0; + m_clipRect.right = dim.x; + m_clipRect.bottom = dim.y; + + return true; +} + +void +CPixmap::CreateMainTexture () +{ + if (!this->mainTexture) + return; + + SDL_DestroyTexture (this->mainTexture); + SDL_SetHint ( + SDL_HINT_RENDER_SCALE_QUALITY, + g_bFullScreen && g_renderQuality ? "best" : "nearest"); + this->mainTexture = SDL_CreateTexture ( + g_renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, LXIMAGE (), + LYIMAGE ()); + SDL_SetHint (SDL_HINT_RENDER_SCALE_QUALITY, "nearest"); +} + +Sint32 +CPixmap::BltFast ( + Sint32 dstCh, size_t srcCh, Rect dstR, Rect srcR, SDL_RendererFlip flip) +{ + Sint32 res; + + SDL_Rect srcRect, dstRect; + srcRect.x = srcR.left; + srcRect.y = srcR.top; + srcRect.w = srcR.right - srcR.left; + srcRect.h = srcR.bottom - srcR.top; + dstRect.x = dstR.left; + dstRect.y = dstR.top; + dstRect.w = dstR.right - dstR.left; + dstRect.h = dstR.bottom - dstR.top; + + auto target = SDL_GetRenderTarget (g_renderer); + + if (dstCh < 0) + { + if (!this->mainTexture && g_bFullScreen && g_zoom == 1) + { + SDL_SetHint ( + SDL_HINT_RENDER_SCALE_QUALITY, g_renderQuality ? "best" : "nearest"); + this->mainTexture = SDL_CreateTexture ( + g_renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, + LXIMAGE (), LYIMAGE ()); + SDL_SetHint (SDL_HINT_RENDER_SCALE_QUALITY, "nearest"); + } + else if (this->mainTexture && !(g_bFullScreen && g_zoom == 1)) + { + SDL_DestroyTexture (this->mainTexture); + this->mainTexture = nullptr; + } + + if (this->mainTexture) + SDL_SetRenderTarget (g_renderer, target ? target : this->mainTexture); + res = SDL_RenderCopyEx ( + g_renderer, m_SDLTextureInfo[srcCh].texture, &srcRect, &dstRect, 0, + nullptr, flip); + if (this->mainTexture) + SDL_SetRenderTarget (g_renderer, target); + } + else + { + SDL_SetRenderTarget (g_renderer, m_SDLTextureInfo[dstCh].texture); + res = SDL_RenderCopyEx ( + g_renderer, m_SDLTextureInfo[srcCh].texture, &srcRect, &dstRect, 0, + nullptr, flip); + SDL_SetRenderTarget (g_renderer, target); + } + + return res; +} + +// Effectue un appel BltFast. +// Les modes sont 0=transparent, 1=opaque. + +Sint32 +CPixmap::BltFast ( + Sint32 chDst, size_t channel, Point dst, Rect rcRect, SDL_RendererFlip flip) +{ + Sint32 limit; + + // Effectue un peu de clipping. + if (dst.x < m_clipRect.left) + { + rcRect.left += m_clipRect.left - dst.x; + dst.x = m_clipRect.left; + } + limit = (m_clipRect.right - dst.x) + rcRect.left; + if (rcRect.right > limit) + rcRect.right = limit; + if (dst.y < m_clipRect.top) + { + rcRect.top += m_clipRect.top - dst.y; + dst.y = m_clipRect.top; + } + limit = (m_clipRect.bottom - dst.y) + rcRect.top; + if (rcRect.bottom > limit) + rcRect.bottom = limit; + + if (rcRect.left >= rcRect.right || rcRect.top >= rcRect.bottom) + return 0; + + Rect dstRect; + dstRect.left = dst.x; + dstRect.top = dst.y; + dstRect.right = dstRect.left + rcRect.right - rcRect.left; + dstRect.bottom = dstRect.top + rcRect.bottom - rcRect.top; + return this->BltFast (chDst, channel, dstRect, rcRect, flip); +} + +// Effectue un appel BltFast. +// Les modes sont 0=transparent, 1=opaque. + +Sint32 +CPixmap::BltFast ( + SDL_Texture * lpSDL, size_t channel, Point dst, Rect rcRect, + SDL_BlendMode mode) +{ + Sint32 res; + + SDL_Rect srcRect, dstRect; + srcRect.x = rcRect.left; + srcRect.y = rcRect.top; + srcRect.w = rcRect.right - rcRect.left; + srcRect.h = rcRect.bottom - rcRect.top; + dstRect = srcRect; + dstRect.x = dst.x; + dstRect.y = dst.y; + + SDL_BlendMode oMode; + SDL_GetTextureBlendMode (m_SDLTextureInfo[channel].texture, &oMode); + if (oMode != mode) + SDL_SetTextureBlendMode (m_SDLTextureInfo[channel].texture, mode); + + SDL_SetRenderTarget (g_renderer, lpSDL); + res = SDL_RenderCopy ( + g_renderer, m_SDLTextureInfo[channel].texture, &srcRect, &dstRect); + SDL_SetRenderTarget (g_renderer, nullptr); + + if (oMode != mode) + SDL_SetTextureBlendMode (m_SDLTextureInfo[channel].texture, oMode); + + return res; +} + +/** + * \brief Reload textures created with access target flag. + * + * \returns true on success. + */ +bool +CPixmap::ReloadTargetTextures () +{ + if (this->mainTexture) + { + SDL_DestroyTexture (this->mainTexture); + this->mainTexture = nullptr; + } + + for (auto & tex : m_SDLTextureInfo) + { + if (!tex.second.target) + continue; + + if (tex.second.file.empty ()) + { + if (!Cache (tex.first, tex.second.dimTotal)) + return false; + } + else if (!Cache ( + tex.first, tex.second.file, tex.second.dimTotal, + tex.second.dimIcon, Mode::FIX, tex.second.wideName)) + return false; + } + + return true; +} + +bool +CPixmap::Cache (size_t channel, Point totalDim) +{ + if (m_SDLTextureInfo.find (channel) == m_SDLTextureInfo.end ()) + { + m_SDLTextureInfo[channel].texture = SDL_CreateTexture ( + g_renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, totalDim.x, + totalDim.y); + + if (!m_SDLTextureInfo[channel].texture) + { + SDL_LogError ( + SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture: %s", + SDL_GetError ()); + return false; + } + + SDL_SetTextureBlendMode ( + m_SDLTextureInfo[channel].texture, SDL_BLENDMODE_BLEND); + } + else + { + SDL_SetRenderTarget (g_renderer, m_SDLTextureInfo[channel].texture); + SDL_SetRenderDrawColor (g_renderer, 0, 0, 0, 0); + SDL_RenderClear (g_renderer); + SDL_SetRenderTarget (g_renderer, nullptr); + } + + m_SDLTextureInfo[channel].texMask = nullptr; + m_SDLTextureInfo[channel].target = true; + m_SDLTextureInfo[channel].dimIcon = Point{0, 0}; + m_SDLTextureInfo[channel].dimTotal = totalDim; + m_SDLTextureInfo[channel].file = ""; + m_SDLTextureInfo[channel].wideName = ""; + + return true; +} + +// Cache une image contenant des ic�nes. + +bool +CPixmap::Cache ( + size_t channel, const std::string & pFilename, Point totalDim, Point iconDim, + Mode mode, std::string wideName) +{ + std::string absolute; + std::string file = GetBaseDir () + "image/" + GetLocale () + "/" + pFilename; + if (!FileExists (file, file, LOCATION_ABSOLUTE)) + file = GetBaseDir () + "image/" + pFilename; + + SDL_Surface * surface = IMG_Load (file.c_str ()); + bool blupiChSet = false; + + if (channel == CHBLUPI && !m_lpSDLBlupi) + { + m_lpSDLBlupi = surface; + blupiChSet = true; + } + + SDL_Texture * texture = SDL_CreateTextureFromSurface (g_renderer, surface); + Uint32 format; + Sint32 access, ow, w, oh, h; + SDL_QueryTexture (texture, &format, &access, &ow, &oh); + + auto m = mode == EXPAND || channel == CHBACK; + w = m ? LXIMAGE () : ow; + h = m ? LYIMAGE () : oh; + + if (m_SDLTextureInfo.find (channel) == m_SDLTextureInfo.end ()) + { + m_SDLTextureInfo[channel].texture = SDL_CreateTexture ( + g_renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, w, h); + + if (!m_SDLTextureInfo[channel].texture) + { + SDL_LogError ( + SDL_LOG_CATEGORY_APPLICATION, + "Couldn't create texture from surface: %s", SDL_GetError ()); + return false; + } + + if (channel != CHBACK) + SDL_SetTextureBlendMode ( + m_SDLTextureInfo[channel].texture, SDL_BLENDMODE_BLEND); + } + + SDL_SetRenderTarget (g_renderer, m_SDLTextureInfo[channel].texture); + SDL_SetRenderDrawColor (g_renderer, 0, 0, 0, 0); + SDL_RenderClear (g_renderer); + SDL_SetRenderTarget (g_renderer, nullptr); + + m_SDLTextureInfo[channel].texMask = channel == CHMASK2 ? texture : nullptr; + m_SDLTextureInfo[channel].target = true; + m_SDLTextureInfo[channel].dimIcon = iconDim; + m_SDLTextureInfo[channel].dimTotal = totalDim; + m_SDLTextureInfo[channel].file = pFilename; + m_SDLTextureInfo[channel].wideName = wideName; + + SDL_SetRenderTarget (g_renderer, m_SDLTextureInfo[channel].texture); + + SDL_RendererFlip flip = + (mode == FIX_REVERSABLE || mode == EXPAND_REVERSABLE) && IsRightReading () + ? SDL_FLIP_HORIZONTAL + : SDL_FLIP_NONE; + + switch (mode) + { + case FIX: + case FIX_REVERSABLE: + { + if (channel == CHBACK && (ow < LXIMAGE () || oh < LYIMAGE ())) + { + if (!wideName.empty ()) + { + std::string file = + GetBaseDir () + "image/" + m_SDLTextureInfo[channel].wideName; + SDL_Surface * surface = IMG_Load (file.c_str ()); + SDL_Texture * texture = + SDL_CreateTextureFromSurface (g_renderer, surface); + SDL_FreeSurface (surface); + SDL_RenderCopyEx ( + g_renderer, texture, nullptr, nullptr, 0, nullptr, flip); + SDL_DestroyTexture (texture); + } + + SDL_Rect dst; + dst.x = (LXIMAGE () - ow) / 2; + dst.y = 0; + dst.w = ow; + dst.h = oh; + SDL_RenderCopyEx (g_renderer, texture, nullptr, &dst, 0, nullptr, flip); + } + else + SDL_RenderCopyEx ( + g_renderer, texture, nullptr, nullptr, 0, nullptr, flip); + break; + } + + case EXPAND: + case EXPAND_REVERSABLE: + { + auto isFlipped = flip == SDL_FLIP_HORIZONTAL; + + SDL_Rect src, dst; + src.x = 0; + src.y = 0; + src.w = POSDRAWX_ - 1; + src.h = LYIMAGE (); + dst = src; + dst.x = isFlipped ? LXIMAGE () - src.w : src.x; + SDL_RenderCopyEx (g_renderer, texture, &src, &dst, 0, nullptr, flip); + src.x = ow - 16; + src.w = 16; + dst.x = isFlipped ? 0 : LXIMAGE () - 16; + dst.w = src.w; + SDL_RenderCopyEx (g_renderer, texture, &src, &dst, 0, nullptr, flip); + src.x = POSDRAWX_ - 1; + src.w = ow - src.x - 16; + dst.x = isFlipped ? 16 : src.x; + dst.w = DIMDRAWX + 1; + SDL_RenderCopyEx (g_renderer, texture, &src, &dst, 0, nullptr, flip); + break; + } + } + + SDL_SetRenderTarget (g_renderer, nullptr); + + if (!m_SDLTextureInfo[channel].texMask) + SDL_DestroyTexture (texture); + + if (!blupiChSet) + SDL_FreeSurface (surface); + + return true; +} + +// Cache une image globale. + +bool +CPixmap::Cache (size_t channel, const std::string & pFilename, Point totalDim) +{ + Point iconDim; + + iconDim.x = 0; + iconDim.y = 0; + + return Cache (channel, pFilename, totalDim, iconDim); +} + +// Cache une image provenant d'un bitmap. + +bool +CPixmap::Cache (size_t channel, SDL_Surface * surface, Point totalDim) +{ + // Create the offscreen surface, by loading our bitmap. + if ( + m_SDLTextureInfo.find (channel) != m_SDLTextureInfo.end () && + m_SDLTextureInfo[channel].texture) + SDL_DestroyTexture (m_SDLTextureInfo[channel].texture); + + m_SDLTextureInfo[channel].texture = + SDL_CreateTextureFromSurface (g_renderer, surface); + m_SDLTextureInfo[channel].target = false; + + if (!m_SDLTextureInfo[channel].texture) + return false; + + m_SDLTextureInfo[channel].dimTotal = totalDim; + m_SDLTextureInfo[channel].dimIcon = totalDim; + return true; +} + +SDL_Texture * +CPixmap::getTexture (size_t channel) +{ + auto it = this->m_SDLTextureInfo.find (channel); + if (it == this->m_SDLTextureInfo.end ()) + return nullptr; + + return it->second.texture; +} + +// Modifie la r�gion de clipping. + +void +CPixmap::SetClipping (Rect clip) +{ + m_clipRect = clip; +} + +// Retourne la r�gion de clipping. + +Rect +CPixmap::GetClipping () +{ + return m_clipRect; +} + +// Teste si un point fait partie d'une ic�ne. + +bool +CPixmap::IsIconPixel (size_t channel, Sint32 rank, Point pos) +{ + Sint32 nbx, nby; + + auto texInfo = m_SDLTextureInfo.find (channel); + if (texInfo == m_SDLTextureInfo.end ()) + return false; + + if (texInfo->second.dimIcon.x == 0 || texInfo->second.dimIcon.y == 0) + return false; + + nbx = texInfo->second.dimTotal.x / texInfo->second.dimIcon.x; + nby = texInfo->second.dimTotal.y / texInfo->second.dimIcon.y; + + if (rank < 0 || rank >= nbx * nby) + return false; + + pos.x += (rank % nbx) * texInfo->second.dimIcon.x; + pos.y += (rank / nbx) * texInfo->second.dimIcon.y; + + SDL_Rect rect; + rect.x = pos.x; + rect.y = pos.y; + rect.w = 1; + rect.h = 1; + Uint32 pixel = 0; + + SDL_SetRenderTarget (g_renderer, m_SDLTextureInfo[channel].texture); + SDL_RenderReadPixels (g_renderer, &rect, 0, &pixel, 4); + SDL_SetRenderTarget (g_renderer, nullptr); + + return !!pixel; +} + +// Dessine une partie d'image rectangulaire. +// Les modes sont 0=transparent, 1=opaque. + +bool +CPixmap::DrawIcon (Sint32 chDst, size_t channel, Sint32 rank, Point pos) +{ + Sint32 nbx, nby; + Rect rect; + + auto texInfo = m_SDLTextureInfo.find (channel); + if (channel != CHMAP && texInfo == m_SDLTextureInfo.end ()) + return false; + + if (texInfo->second.dimIcon.x == 0 || texInfo->second.dimIcon.y == 0) + return false; + + nbx = texInfo->second.dimTotal.x / texInfo->second.dimIcon.x; + nby = texInfo->second.dimTotal.y / texInfo->second.dimIcon.y; + + if (rank < 0 || rank >= nbx * nby) + return false; + + rect.left = (rank % nbx) * texInfo->second.dimIcon.x; + rect.top = (rank / nbx) * texInfo->second.dimIcon.y; + rect.right = rect.left + texInfo->second.dimIcon.x; + rect.bottom = rect.top + texInfo->second.dimIcon.y; + + return !BltFast (chDst, channel, pos, rect); +} + +// Dessine une partie d'image rectangulaire. +// Les modes sont 0=transparent, 1=opaque. +// +// Correspondances in,out : +// 0,0 2,1 ... +// 1,16 3,17 +// +// 32,32 34,33 +// 33,48 35,49 + +bool +CPixmap::DrawIconDemi (Sint32 chDst, size_t channel, Sint32 rank, Point pos) +{ + Sint32 nbx, nby; + Rect rect; + + auto texInfo = m_SDLTextureInfo.find (channel); + if (texInfo == m_SDLTextureInfo.end ()) + return false; + + if (texInfo->second.dimIcon.x == 0 || texInfo->second.dimIcon.y == 0) + return false; + + nbx = texInfo->second.dimTotal.x / texInfo->second.dimIcon.x; + nby = texInfo->second.dimTotal.y / (texInfo->second.dimIcon.y / 2); + + rank = (rank / 32) * 32 + ((rank % 32) / 2) + ((rank % 2) * 16); + + if (rank < 0 || rank >= nbx * nby) + return false; + + rect.left = (rank % nbx) * texInfo->second.dimIcon.x; + rect.top = (rank / nbx) * (texInfo->second.dimIcon.y / 2); + rect.right = rect.left + texInfo->second.dimIcon.x; + rect.bottom = rect.top + (texInfo->second.dimIcon.y / 2); + + return !BltFast (chDst, channel, pos, rect); +} + +// Dessine une partie d'image rectangulaire. + +bool +CPixmap::DrawIconPart ( + Sint32 chDst, size_t channel, Sint32 rank, Point pos, Sint32 startY, + Sint32 endY) +{ + Sint32 nbx, nby; + Rect rect; + + auto texInfo = m_SDLTextureInfo.find (channel); + if (texInfo == m_SDLTextureInfo.end ()) + return false; + + if (texInfo->second.dimIcon.x == 0 || texInfo->second.dimIcon.y == 0) + return false; + + nbx = texInfo->second.dimTotal.x / texInfo->second.dimIcon.x; + nby = texInfo->second.dimTotal.y / texInfo->second.dimIcon.y; + + if (rank < 0 || rank >= nbx * nby) + return false; + + rect.left = (rank % nbx) * texInfo->second.dimIcon.x; + rect.top = (rank / nbx) * texInfo->second.dimIcon.y; + rect.right = rect.left + texInfo->second.dimIcon.x; + rect.bottom = rect.top + endY; + + pos.y += startY; + rect.top += startY; + + return !BltFast (chDst, channel, pos, rect); +} + +// Dessine une partie d'image n'importe o�. + +bool +CPixmap::DrawPart ( + Sint32 chDst, size_t channel, Point dest, Rect rect, SDL_RendererFlip flip) +{ + if (m_SDLTextureInfo.find (channel) == m_SDLTextureInfo.end ()) + return false; + + return !BltFast (chDst, channel, dest, rect, flip); +} + +// Dessine une partie d'image rectangulaire. + +bool +CPixmap::DrawImage (Sint32 chDst, size_t channel, Rect rect) +{ + Point dst; + Sint32 res; + + if (m_SDLTextureInfo.find (channel) == m_SDLTextureInfo.end ()) + return false; + + dst.x = rect.left; + dst.y = rect.top; + + res = BltFast (chDst, channel, dst, rect); + + if (res) + return false; + + if (channel == CHBACK) + m_bBackDisplayed = false; + + return true; +} + +// Construit une ic�ne en utilisant un masque. + +bool +CPixmap::BuildIconMask ( + size_t channelMask, Sint32 rankMask, size_t channel, Sint32 rankSrc, + Sint32 rankDst) +{ + Sint32 nbx, nby; + Point posDst, posDstMask; + Rect rect, rectMask; + Sint32 res; + + auto texInfo = m_SDLTextureInfo.find (channel); + if (texInfo == m_SDLTextureInfo.end ()) + return false; + + if (texInfo->second.dimIcon.x == 0 || texInfo->second.dimIcon.y == 0) + return false; + + nbx = texInfo->second.dimTotal.x / texInfo->second.dimIcon.x; + nby = texInfo->second.dimTotal.y / texInfo->second.dimIcon.y; + + if (rankSrc < 0 || rankSrc >= nbx * nby) + return false; + if (rankDst < 0 || rankDst >= nbx * nby) + return false; + + rect.left = (rankSrc % nbx) * texInfo->second.dimIcon.x; + rect.top = (rankSrc / nbx) * texInfo->second.dimIcon.y; + rect.right = rect.left + texInfo->second.dimIcon.x; + rect.bottom = rect.top + texInfo->second.dimIcon.y; + posDst.x = (rankDst % nbx) * texInfo->second.dimIcon.x; + posDst.y = (rankDst / nbx) * texInfo->second.dimIcon.y; + + res = BltFast (m_SDLTextureInfo[channel].texture, channel, posDst, rect); + if (res) + return false; + + auto texMaskInfo = m_SDLTextureInfo.find (channelMask); + + if (texMaskInfo->second.dimIcon.x == 0 || texMaskInfo->second.dimIcon.y == 0) + return false; + + nbx = texMaskInfo->second.dimTotal.x / texMaskInfo->second.dimIcon.x; + nby = texMaskInfo->second.dimTotal.y / texMaskInfo->second.dimIcon.y; + + /* Support only CHMASK1 (white) because it needs CHMASK2 (black) (hardcoded + * here) */ + if (rankMask < 0 || rankMask >= nbx * nby || channelMask != CHMASK1) + return false; + + rectMask.left = (rankMask % nbx) * texMaskInfo->second.dimIcon.x; + rectMask.top = (rankMask / nbx) * texMaskInfo->second.dimIcon.y; + rectMask.right = rectMask.left + texMaskInfo->second.dimIcon.x; + rectMask.bottom = rectMask.top + texMaskInfo->second.dimIcon.y; + + /* Multiply the white mask with the texture (no alpha) */ + res = BltFast ( + m_SDLTextureInfo[channel].texture, channelMask, posDst, rectMask, + SDL_BLENDMODE_MOD); + + posDstMask.x = (rankMask % nbx) * texMaskInfo->second.dimIcon.x; + posDstMask.y = (rankMask / nbx) * texMaskInfo->second.dimIcon.y; + /* Addition the previous texture with the black mask (alpha retrieved) */ + res = BltFast ( + m_SDLTextureInfo[CHMASK2].texture, channel, posDstMask, rect, + SDL_BLENDMODE_ADD); + + /* Blit the altered mask in the final texture */ + res = BltFast ( + m_SDLTextureInfo[channel].texture, CHMASK2, posDst, rectMask, + SDL_BLENDMODE_NONE); + + /* Restore the black mask for the next iteration. */ + SDL_SetRenderTarget (g_renderer, m_SDLTextureInfo[CHMASK2].texture); + SDL_RenderCopy ( + g_renderer, m_SDLTextureInfo[CHMASK2].texMask, nullptr, nullptr); + SDL_SetRenderTarget (g_renderer, nullptr); + + return !res; +} + +// Affiche le pixmap � l'�cran. +// Retourne false en cas d'erreur. + +bool +CPixmap::Display () +{ + m_bBackDisplayed = true; + + if (this->mainTexture) + SDL_RenderCopy (g_renderer, this->mainTexture, nullptr, nullptr); + + SDL_RenderPresent (g_renderer); + return true; +} + +// Change le lutin de la souris. + +void +CPixmap::SetMouseSprite (MouseSprites sprite) +{ + if (m_mouseSprite == sprite) + return; + + m_mouseSprite = sprite; + + SDL_SetCursor (m_lpSDLCursors[sprite - 1]); +} + +// Montre ou cache la souris. + +void +CPixmap::MouseShow (bool bShow) +{ + SDL_ShowCursor (bShow); +} + +// Retourne le rectangle correspondant au sprite +// de la souris dans CHBLUPI. + +Rect +CPixmap::MouseRectSprite () +{ + Sint32 rank, nbx; + Rect rcRect; + + rank = 348; + if (m_mouseSprite == SPRITE_ARROW) + rank = 348; + if (m_mouseSprite == SPRITE_POINTER) + rank = 349; + if (m_mouseSprite == SPRITE_MAP) + rank = 350; + if (m_mouseSprite == SPRITE_WAIT) + rank = 351; + if (m_mouseSprite == SPRITE_FILL) + rank = 352; + if (m_mouseSprite == SPRITE_ARROWL) + rank = 353; + if (m_mouseSprite == SPRITE_ARROWR) + rank = 354; + if (m_mouseSprite == SPRITE_ARROWU) + rank = 355; + if (m_mouseSprite == SPRITE_ARROWD) + rank = 356; + if (m_mouseSprite == SPRITE_ARROWDL) + rank = 357; + if (m_mouseSprite == SPRITE_ARROWDR) + rank = 358; + if (m_mouseSprite == SPRITE_ARROWUL) + rank = 359; + if (m_mouseSprite == SPRITE_ARROWUR) + rank = 360; + + auto texMaskInfo = m_SDLTextureInfo.find (CHBLUPI); + + nbx = texMaskInfo->second.dimTotal.x / texMaskInfo->second.dimIcon.x; + + rcRect.left = (rank % nbx) * texMaskInfo->second.dimIcon.x; + rcRect.top = (rank / nbx) * texMaskInfo->second.dimIcon.y; + rcRect.right = rcRect.left + texMaskInfo->second.dimIcon.x; + rcRect.bottom = rcRect.top + texMaskInfo->second.dimIcon.y; + + return rcRect; +} + +SDL_Point +CPixmap::GetCursorHotSpot (MouseSprites sprite) +{ + static const Sint32 hotspots[MAXCURSORS * 2] = { + 30, 30, // SPRITE_ARROW + 20, 15, // SPRITE_POINTER + 31, 26, // SPRITE_MAP + 25, 14, // SPRITE_ARROWU + 24, 35, // SPRITE_ARROWD + 15, 24, // SPRITE_ARROWL + 35, 24, // SPRITE_ARROWR + 18, 16, // SPRITE_ARROWUL + 32, 18, // SPRITE_ARROWUR + 17, 30, // SPRITE_ARROWDL + 32, 32, // SPRITE_ARROWDR + 30, 30, // SPRITE_WAIT + 30, 30, // SPRITE_EMPTY + 21, 51, // SPRITE_FILL + }; + + SDL_Point hotspot = {0, 0}; + + if (sprite >= SPRITE_BEGIN && sprite <= SPRITE_END) + { + const Sint32 rank = sprite - SPRITE_BEGIN; // rank <- 0..n + + hotspot.x = hotspots[rank * 2 + 0]; + hotspot.y = hotspots[rank * 2 + 1]; + } + + return hotspot; +} + +SDL_Rect +CPixmap::GetCursorRect (MouseSprites sprite) +{ + Sint32 rank; + SDL_Rect rcRect; + + switch (sprite) + { + default: + case SPRITE_ARROW: + rank = 348; + break; + case SPRITE_POINTER: + rank = 349; + break; + case SPRITE_MAP: + rank = 350; + break; + case SPRITE_WAIT: + rank = 351; + break; + case SPRITE_FILL: + rank = 352; + break; + case SPRITE_ARROWL: + rank = 353; + break; + case SPRITE_ARROWR: + rank = 354; + break; + case SPRITE_ARROWU: + rank = 355; + break; + case SPRITE_ARROWD: + rank = 356; + break; + case SPRITE_ARROWDL: + rank = 357; + break; + case SPRITE_ARROWDR: + rank = 358; + break; + case SPRITE_ARROWUL: + rank = 359; + break; + case SPRITE_ARROWUR: + rank = 360; + break; + } + + auto texMaskInfo = m_SDLTextureInfo.find (CHBLUPI); + + Sint32 nbx = texMaskInfo->second.dimTotal.x / texMaskInfo->second.dimIcon.x; + + rcRect.x = (rank % nbx) * texMaskInfo->second.dimIcon.x; + rcRect.y = (rank / nbx) * texMaskInfo->second.dimIcon.y; + rcRect.w = texMaskInfo->second.dimIcon.x; + rcRect.h = texMaskInfo->second.dimIcon.y; + + return rcRect; +} + +void +CPixmap::LoadCursors () +{ + Uint32 rmask, gmask, bmask, amask; + + /* SDL interprets each pixel as a 32-bit number, so our masks must depend + * on the endianness (byte order) of the machine + */ +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + rmask = 0xff000000; + gmask = 0x00ff0000; + bmask = 0x0000ff00; + amask = 0x000000ff; +#else /* SDL_BYTEORDER == SDL_BIG_ENDIAN */ + rmask = 0x000000ff; + gmask = 0x0000ff00; + bmask = 0x00ff0000; + amask = 0xff000000; +#endif /* SDL_BYTEORDER != SDL_BIG_ENDIAN */ + + auto scale = this->GetDisplayScale (); + + for (int i = SPRITE_BEGIN; i <= SPRITE_END; ++i) + { + MouseSprites sprite = static_cast (i); + + if (m_lpSDLCursors[sprite - 1]) + SDL_FreeCursor (m_lpSDLCursors[sprite - 1]); + + SDL_Point hotspot = this->GetCursorHotSpot (sprite); + SDL_Rect rect = this->GetCursorRect (sprite); + + SDL_Surface * surface = SDL_CreateRGBSurface ( + 0, rect.w * scale, rect.h * scale, 32, rmask, gmask, bmask, amask); + SDL_BlitScaled (m_lpSDLBlupi, &rect, surface, nullptr); + + // FIXME: change cursor first value to 0 + m_lpSDLCursors[sprite - 1] = + SDL_CreateColorCursor (surface, hotspot.x * scale, hotspot.y * scale); + SDL_FreeSurface (surface); + } +} + +void +CPixmap::ChangeSprite (MouseSprites sprite) +{ + if (m_lpCurrentCursor == m_lpSDLCursors[sprite - 1]) + return; + + SDL_SetCursor (m_lpSDLCursors[sprite - 1]); + m_lpCurrentCursor = m_lpSDLCursors[sprite - 1]; +} + +double +CPixmap::GetDisplayScale () +{ + Sint32 w, h; + SDL_GetWindowSize (g_window, &w, &h); + return static_cast (h / LYIMAGE ()); +} + +void +CPixmap::FromDisplayToGame (Sint32 & x, Sint32 & y, double prevScale) +{ + if (this->event->IsDemoPlaying ()) + return; + + double factor = 1; + + if (!g_bFullScreen) + factor = prevScale; + + x /= factor; + y /= factor; +} + +void +CPixmap::FromGameToDisplay (Sint32 & x, Sint32 & y) +{ + double factor = 1; + + if (!g_bFullScreen) + factor = g_zoom; + + x *= factor; + y *= factor; + + if (!g_bFullScreen) + return; + + Sint32 w, h; + SDL_GetWindowSize (g_window, &w, &h); + + double _w = w, _h = h; + + x = x * _w / LXIMAGE (); + y = y * _h / LYIMAGE (); +} diff --git a/src/pixmap.h b/src/pixmap.h new file mode 100644 index 0000000..dd47bc9 --- /dev/null +++ b/src/pixmap.h @@ -0,0 +1,139 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include +#include +#include + +#include "blupi.h" +#include "def.h" + +#define MAXCURSORS 14 + +struct TextureInfo { + SDL_Texture * texMask; + SDL_Texture * texture; + bool target; // can be used as a render target + std::string file; + std::string wideName; + Point dimTotal; + Point dimIcon; + + TextureInfo () + : texMask (nullptr) + , texture (nullptr) + , target (false) + , dimTotal{0} + , dimIcon{0} + { + } +}; + +class CEvent; + +class CPixmap +{ +public: + enum Mode { + FIX = 0, + FIX_REVERSABLE, + EXPAND, + EXPAND_REVERSABLE, + }; + + CPixmap (CEvent * event); + ~CPixmap (); + + bool Create (Point dim); + + void CreateMainTexture (); + bool ReloadTargetTextures (); + bool Cache (size_t channel, Point totalDim); + bool Cache ( + size_t channel, const std::string & pFilename, Point totalDim, + Point iconDim, Mode mode = FIX, std::string wideName = ""); + bool Cache (size_t channel, const std::string & pFilename, Point totalDim); + bool Cache (size_t channel, SDL_Surface * surface, Point totalDim); + SDL_Texture * getTexture (size_t channel); + void SetClipping (Rect clip); + Rect GetClipping (); + + bool IsIconPixel (size_t channel, Sint32 rank, Point pos); + + bool DrawIcon (Sint32 chDst, size_t channel, Sint32 rank, Point pos); + bool DrawIconDemi (Sint32 chDst, size_t channel, Sint32 rank, Point pos); + bool DrawIconPart ( + Sint32 chDst, size_t channel, Sint32 rank, Point pos, Sint32 startY, + Sint32 endY); + bool DrawPart ( + Sint32 chDst, size_t channel, Point dest, Rect rect, + SDL_RendererFlip flip = SDL_FLIP_NONE); + bool DrawImage (Sint32 chDst, size_t channel, Rect rect); + + bool BuildIconMask ( + size_t channelMask, Sint32 rankMask, size_t channel, Sint32 rankSrc, + Sint32 rankDst); + + bool Display (); + + void SetMouseSprite (MouseSprites sprite); + void MouseShow (bool bShow); + void LoadCursors (); + void ChangeSprite (MouseSprites sprite); + +public: + double GetDisplayScale (); + void FromDisplayToGame (Sint32 & x, Sint32 & y, double prevScale = 1); + void FromGameToDisplay (Sint32 & x, Sint32 & y); + +protected: + Sint32 BltFast ( + Sint32 dstCh, size_t srcCh, Rect dstR, Rect srcR, + SDL_RendererFlip flip = SDL_FLIP_NONE); + Sint32 BltFast ( + Sint32 chDst, size_t channel, Point dst, Rect rcRect, + SDL_RendererFlip flip = SDL_FLIP_NONE); + Sint32 BltFast ( + SDL_Texture * lpSDL, size_t channel, Point dst, Rect rcRect, + SDL_BlendMode = SDL_BLENDMODE_BLEND); + + Rect MouseRectSprite (); + SDL_Point GetCursorHotSpot (MouseSprites sprite); + SDL_Rect GetCursorRect (MouseSprites sprite); + +protected: + bool m_bDebug; + bool m_bPalette; + Point m_dim; // dimensions totales + Rect m_clipRect; // rectangle de clipping + + MouseSprites m_mouseSprite; + bool m_bBackDisplayed; + + CEvent * event; + + SDL_Cursor * m_lpCurrentCursor; + SDL_Cursor * m_lpSDLCursors[MAXCURSORS]; + SDL_Surface * m_lpSDLBlupi; + SDL_Texture * mainTexture; + std::unordered_map m_SDLTextureInfo; +}; diff --git a/src/platform.h b/src/platform.h new file mode 100644 index 0000000..51fa9ca --- /dev/null +++ b/src/platform.h @@ -0,0 +1,37 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include + +class Platform +{ +private: + static std::function handleEvent; + +private: + static void timer (void *); + +public: + enum Type { JS, SDL }; + + static Platform::Type getType (); + static void run (std::function handleEvent); +}; diff --git a/src/platform/platform_js.cxx b/src/platform/platform_js.cxx new file mode 100644 index 0000000..2917967 --- /dev/null +++ b/src/platform/platform_js.cxx @@ -0,0 +1,58 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include +#include + +#include "../blupi.h" +#include "../event.h" +#include "../platform.h" + +std::function Platform::handleEvent; + +Platform::Type +Platform::getType () +{ + return JS; +} + +void +Platform::run (std::function handleEvent) +{ + Platform::handleEvent = handleEvent; + Platform::timer (nullptr); + emscripten_set_main_loop ( + []() { + SDL_Event event; + while (SDL_PollEvent (&event)) + { + Platform::handleEvent (event); + if (event.type == SDL_QUIT) + break; + } + }, + 0, 1); +} + +void +Platform::timer (void *) +{ + CEvent::PushUserEvent (EV_UPDATE); + emscripten_async_call (Platform::timer, nullptr, g_timerInterval); +} diff --git a/src/platform/platform_sdl.cxx b/src/platform/platform_sdl.cxx new file mode 100644 index 0000000..b0b44cb --- /dev/null +++ b/src/platform/platform_sdl.cxx @@ -0,0 +1,57 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include "../blupi.h" +#include "../event.h" +#include "../platform.h" + +std::function Platform::handleEvent; + +Platform::Type +Platform::getType () +{ + return SDL; +} + +void +Platform::run (std::function handleEvent) +{ + SDL_TimerID updateTimer = SDL_AddTimer ( + g_timerInterval, + [](Uint32 interval, void * param) -> Uint32 { + CEvent::PushUserEvent (EV_UPDATE); + return interval; + }, + nullptr); + + SDL_Event event; + while (SDL_WaitEvent (&event)) + { + handleEvent (event); + if (event.type == SDL_QUIT) + break; + } + + SDL_RemoveTimer (updateTimer); +} + +void +Platform::timer (void *) +{ +} diff --git a/src/progress.cxx b/src/progress.cxx new file mode 100644 index 0000000..8a6b40d --- /dev/null +++ b/src/progress.cxx @@ -0,0 +1,145 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include +#include + +#include "decor.h" +#include "def.h" +#include "misc.h" +#include "pixmap.h" +#include "progress.h" +#include "sound.h" + +CJauge::CJauge () +{ + m_type = 0; + m_bHide = true; + m_pPixmap = nullptr; + m_pDecor = nullptr; + m_pSound = nullptr; +} + +CJauge::~CJauge () {} + +// Crée un nouveau bouton. + +bool +CJauge::Create (CPixmap * pPixmap, CSound * pSound, Point pos, Sint32 type) +{ + m_pPixmap = pPixmap; + m_pSound = pSound; + m_type = type; + m_bHide = true; + m_pos = pos; + m_dim.x = DIMJAUGEX; + m_dim.y = DIMJAUGEY; + m_level = 0; + + return true; +} + +// Dessine un bouton dans son état. + +void +CJauge::Draw () +{ + Sint32 part; + Rect rect; + Point pos = this->m_pos; + + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x - m_dim.x; + + if (m_bHide) // bouton caché ? + { + rect.left = pos.x; + rect.right = pos.x + m_dim.x; + rect.top = pos.y; + rect.bottom = pos.y + m_dim.y; + m_pPixmap->DrawPart (-1, CHBACK, pos, rect); // dessine le fond + return; + } + + SDL_RendererFlip flip = SDL_FLIP_NONE; + if (IsRightReading ()) + flip = SDL_FLIP_HORIZONTAL; + + part = (m_level * (DIMJAUGEX - 6 - 4)) / 100; + + rect.left = 0; + rect.right = DIMJAUGEX; + rect.top = DIMJAUGEY * 0; + rect.bottom = DIMJAUGEY * 1; + m_pPixmap->DrawPart (-1, CHJAUGE, pos, rect, flip); // partie noire + + if (part > 0) + { + if (IsRightReading ()) + pos.x += DIMJAUGEX - part - 6; + rect.left = 0; + rect.right = 6 + part; + rect.top = DIMJAUGEY * m_type; + rect.bottom = DIMJAUGEY * (m_type + 1); + m_pPixmap->DrawPart (-1, CHJAUGE, pos, rect, flip); // partie colorée + } +} + +// Modifie le niveau. + +void +CJauge::SetLevel (Sint32 level) +{ + if (level < 0) + level = 0; + if (level > 100) + level = 100; + + m_level = level; +} + +// Modifie le type. + +void +CJauge::SetType (Sint32 type) +{ + m_type = type; +} + +bool +CJauge::GetHide () +{ + return m_bHide; +} + +void +CJauge::SetHide (bool bHide) +{ + m_bHide = bHide; +} + +Point +CJauge::GetPos () +{ + Point pos = m_pos; + if (IsRightReading ()) + pos.x = LXIMAGE () - pos.x - m_dim.x; + return pos; +} diff --git a/src/progress.h b/src/progress.h new file mode 100644 index 0000000..120ccee --- /dev/null +++ b/src/progress.h @@ -0,0 +1,57 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include "blupi.h" + +class CPixmap; +class CDecor; +class CSound; + +class CJauge +{ +public: + CJauge (); + ~CJauge (); + + bool Create (CPixmap * pPixmap, CSound * pSound, Point pos, Sint32 type); + void Draw (); + + void SetLevel (Sint32 level); + void SetType (Sint32 type); + + bool GetHide (); + void SetHide (bool bHide); + + Point GetPos (); + +protected: + CPixmap * m_pPixmap; + CDecor * m_pDecor; + CSound * m_pSound; + bool m_bHide; // true si bouton caché + Point m_pos; // up/left corner + Point m_dim; // dimensions + Sint32 m_type; + Sint32 m_level; +}; + +///////////////////////////////////////////////////////////////////////////// diff --git a/src/sound.cxx b/src/sound.cxx new file mode 100644 index 0000000..579e724 --- /dev/null +++ b/src/sound.cxx @@ -0,0 +1,446 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2018, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include + +#include "def.h" +#include "event.h" +#include "misc.h" +#include "platform.h" +#include "sound.h" + +void +CSound::StopSound (bool immediat, Sint32 rank) +{ + Sounds stopCh; + + if (rank >= 0 && rank < MAXBLUPI) + { + stopCh = m_channelBlupi[rank]; + if (stopCh >= 0 && m_lpSDL[stopCh] != nullptr) + { + /* FIXME: add support of fade out with emscripten */ + if (immediat || Platform::getType () == Platform::Type::JS) + Mix_HaltChannel (stopCh + 1); + else + Mix_FadeOutChannel (stopCh + 1, 500); + } + + m_channelBlupi[rank] = SOUND_NONE; + } +} + +// Stops all sounds. + +bool +CSound::StopAllSounds (bool immediat, const std::set * except) +{ + for (Sint32 i = 0; i < MAXSOUND; i++) + { + if (!m_lpSDL[i]) + continue; + + if (except && except->find (i) != except->end ()) + continue; + + if (Mix_Playing (i + 1) == SDL_TRUE) + { + /* FIXME: add support of fade out with emscripten */ + if (immediat || Platform::getType () == Platform::Type::JS) + Mix_HaltChannel (i + 1); + else + Mix_FadeOutChannel (i + 1, 500); + } + } + + return true; +} + +CSound::CSound () + : m_sndFiles (MAXSOUND) +{ + Sint32 i; + + m_bState = false; + m_MIDIFilename[0] = 0; + m_audioVolume = 20; + m_midiVolume = 15; + m_lastMidiVolume = 0; + m_pMusic = nullptr; + m_bStopped = false; + + for (i = 0; i < MAXBLUPI; i++) + m_channelBlupi[i] = SOUND_NONE; + + memset (m_lpSDL, 0, sizeof (m_lpSDL)); +} + +// Destructeur. + +CSound::~CSound () +{ + Sint32 i; + + for (i = 0; i < MAXSOUND; i++) + { + if (!m_lpSDL[i]) + continue; + + Mix_FreeChunk (m_lpSDL[i]); + m_lpSDL[i] = nullptr; + } + + if (m_pMusic) + { + Mix_FreeMusic (m_pMusic); + m_pMusic = nullptr; + } + + Mix_CloseAudio (); +} + +// Initialisation de DirectSound. + +bool +CSound::Create () +{ + if ( + Mix_OpenAudio (44100, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, 1024) == -1) + return false; + + Mix_AllocateChannels (MAXSOUND); + + Mix_HookMusicFinished ([]() { CEvent::PushUserEvent (EV_MUSIC_STOP); }); + + return true; +} + +// Enclenche ou d�clenche le son. + +void +CSound::SetState (bool bState) +{ + m_bState = bState; +} + +// Gestion des volumes audio (.wav) et midi (.mid). + +void +CSound::SetAudioVolume (Sint32 volume) +{ + m_audioVolume = volume; +} + +Sint32 +CSound::GetAudioVolume () +{ + return m_audioVolume; +} + +void +CSound::SetMidiVolume (Sint32 volume) +{ + m_midiVolume = volume; +} + +Sint32 +CSound::GetMidiVolume () +{ + return m_midiVolume; +} + +// Cache tous les ficheirs son (.wav). + +void +CSound::CacheAll () +{ + Sint32 i; + char name[50]; + + this->StopAllSounds (true); + + for (i = 0; i < MAXSOUND; i++) + { + snprintf (name, sizeof (name), "sound%.3d.wav", i); + if (!Cache (i, name)) + break; + } +} + +// Charge un fichier son (.wav). + +bool +CSound::Cache (Sint32 channel, const std::string & pFilename) +{ + if (channel < 0 || channel >= MAXSOUND) + return false; + + auto sound = "sound/" + GetLocale () + "/" + pFilename; + auto file = GetBaseDir () + sound; + + if (m_lpSDL[channel] && m_sndFiles[channel] == sound) + return true; + + Mix_Chunk * chunk = nullptr; + std::string absolute; + + if (FileExists (file, absolute, Location::LOCATION_ABSOLUTE)) + chunk = Mix_LoadWAV (file.c_str ()); + + if (!chunk) + { + if (GetLocale () != "en") + { + /* Try with the fallback locale */ + sound = "sound/en/" + pFilename; + file = GetBaseDir () + sound; + + if (m_lpSDL[channel] && m_sndFiles[channel] == sound) + return true; + + chunk = Mix_LoadWAV (file.c_str ()); + if (!chunk) + goto err; + } + else + goto err; + } + + if (m_lpSDL[channel]) + Flush (channel); + + m_lpSDL[channel] = chunk; + m_sndFiles[channel] = sound; + + SDL_Log ("Load sound: %s\n", sound.c_str ()); + return true; + +err: + SDL_Log ("Mix_LoadWAV: %s\n", Mix_GetError ()); + return false; +} + +void +CSound::FlushAll () +{ + for (size_t ch = 0; ch < sizeof (m_lpSDL); ++ch) + Flush (ch); +} + +// D�charge un son. + +void +CSound::Flush (Sint32 channel) +{ + if (channel < 0 || channel >= MAXSOUND) + return; + + if (m_lpSDL[channel]) + { + Mix_FreeChunk (m_lpSDL[channel]); + m_lpSDL[channel] = nullptr; + } +} + +// Fait entendre un son. +// Le volume est compris entre 128 (max) et 0 (silence). +// Le panoramique est compris entre 255,0 (gauche), 127,128 (centre) +// et 0,255 (droite). + +bool +CSound::Play (Sint32 channel, Sint32 volume, Uint8 panLeft, Uint8 panRight) +{ + if (!m_bState || !m_audioVolume) + return true; + + if (channel < 0 || channel >= MAXSOUND) + return false; + + Mix_SetPanning (channel + 1, panLeft, panRight); + + volume = volume * 100 * m_audioVolume / 20 / 100; + Mix_Volume (channel + 1, volume); + + if (Mix_Playing (channel + 1) == SDL_FALSE) + Mix_PlayChannel (channel + 1, m_lpSDL[channel], 0); + + return true; +} + +// Fait entendre un son dans une image. +// Si rank != -1, il indique le rang du blupi dont il faudra +// �ventuellement stopper le dernier son en cours ! + +bool +CSound::PlayImage (Sounds channel, Point pos, Sint32 rank, bool stop) +{ + Sint32 volumex, volumey, volume; + + if (rank >= 0 && rank < MAXBLUPI) + { + bool immediat = channel == SOUND_DYNAMITE; + + if (stop || immediat) + this->StopSound (immediat, rank); + else + m_channelBlupi[rank] = channel; + } + + Uint8 panRight, panLeft; + volumex = MIX_MAX_VOLUME; + volumey = MIX_MAX_VOLUME; + + if (pos.x < 0) + { + panRight = 0; + panLeft = 255; + volumex += pos.x; + if (volumex < 0) + volumex = 0; + } + else if (pos.x > LXIMAGE ()) + { + panRight = 255; + panLeft = 0; + volumex -= pos.x - LXIMAGE (); + if (volumex < 0) + volumex = 0; + } + else + { + panRight = 255 * static_cast (pos.x) / LXIMAGE (); + panLeft = 255 - panRight; + } + + if (pos.y < 0) + { + volumey += pos.y; + if (volumey < 0) + volumey = 0; + } + else if (pos.y > LYIMAGE ()) + { + volumey -= pos.y - LYIMAGE (); + if (volumey < 0) + volumey = 0; + } + + volume = volumex < volumey ? volumex : volumey; + + return Play (channel, volume, panLeft, panRight); +} + +// Uses MCI to play a MIDI file. The window procedure +// is notified when playback is complete. + +bool +CSound::PlayMusic (const std::string & lpszMIDIFilename) +{ + if (m_midiVolume == 0) + return true; + + if (lpszMIDIFilename.empty ()) + return false; + + Mix_VolumeMusic (MIX_MAX_VOLUME * 100 * m_midiVolume / 20 / 100); + m_lastMidiVolume = m_midiVolume; + + if (m_pMusic) + Mix_FreeMusic (m_pMusic); + + std::string absolute; + if (FileExists (lpszMIDIFilename, absolute, Location::LOCATION_ABSOLUTE)) + m_pMusic = Mix_LoadMUS (lpszMIDIFilename.c_str ()); + + if (!m_pMusic) + { + printf ("%s\n", Mix_GetError ()); + return false; + } + + if (Mix_PlayMusic (m_pMusic, 0) == -1) + { + printf ("%s\n", Mix_GetError ()); + return false; + } + + m_bStopped = false; + m_MIDIFilename = lpszMIDIFilename; + return true; +} + +// Restart the MIDI player. + +bool +CSound::RestartMusic () +{ + OutputDebug ("RestartMusic\n"); + + if (m_midiVolume == 0) + return true; + if (m_MIDIFilename[0] == 0) + return false; + + return PlayMusic (m_MIDIFilename); +} + +// Shuts down the MIDI player. + +void +CSound::SuspendMusic () +{ + m_bStopped = true; + Mix_HaltMusic (); +} + +// Shuts down the MIDI player. + +void +CSound::StopMusic () +{ + SuspendMusic (); + m_MIDIFilename[0] = 0; +} + +// Retourne true si une musique est en cours. + +bool +CSound::IsPlayingMusic () +{ + return (m_MIDIFilename[0] != 0); +} + +bool +CSound::IsStoppedOnDemand () +{ + return m_bStopped; +} + +// Adapte le volume de la musique en cours, si n�cessaire. + +void +CSound::AdaptVolumeMusic () +{ + if (m_midiVolume != m_lastMidiVolume) + { + Mix_VolumeMusic (MIX_MAX_VOLUME * 100 * m_midiVolume / 20 / 100); + m_lastMidiVolume = m_midiVolume; + } +} diff --git a/src/sound.h b/src/sound.h new file mode 100644 index 0000000..b2f6edb --- /dev/null +++ b/src/sound.h @@ -0,0 +1,86 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2019, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +#include +#include +#include +#include + +#ifdef EMSCRIPTEN +#include +#else /* EMSCRIPTEN */ +#include +#endif /* !EMSCRIPTEN */ + +#include "blupi.h" + +#define MAXSOUND 100 +#define MAXVOLUME 20 +#define MAXBLUPI 100 + +class CSound +{ +public: + CSound (); + ~CSound (); + + bool Create (); + void SetState (bool bState); + bool GetEnable (); + + void SetAudioVolume (Sint32 volume); + Sint32 GetAudioVolume (); + void SetMidiVolume (Sint32 volume); + Sint32 GetMidiVolume (); + + void CacheAll (); + bool Cache (Sint32 channel, const std::string & pFilename); + void FlushAll (); + void Flush (Sint32 channel); + + bool Play ( + Sint32 channel, Sint32 volume = 0, Uint8 panLeft = 255, + Uint8 panRight = 255); + bool + PlayImage (Sounds channel, Point pos, Sint32 rank = -1, bool stop = false); + bool PlayMusic (const std::string & lpszMIDIFilename); + bool RestartMusic (); + void SuspendMusic (); + void StopMusic (); + bool IsPlayingMusic (); + bool IsStoppedOnDemand (); + void AdaptVolumeMusic (); + void StopSound (bool immediat, Sint32 rank); + bool StopAllSounds (bool immediat, const std::set * except = nullptr); + +protected: + bool m_bState; + bool m_bStopped; + Mix_Music * m_pMusic; + Mix_Chunk * m_lpSDL[MAXSOUND]; + std::vector m_sndFiles; + Sounds m_channelBlupi[MAXBLUPI]; + std::string m_MIDIFilename; + Sint32 m_audioVolume; + Sint32 m_midiVolume; + Sint32 m_lastMidiVolume; +}; diff --git a/src/text.cxx b/src/text.cxx new file mode 100644 index 0000000..d0a089a --- /dev/null +++ b/src/text.cxx @@ -0,0 +1,502 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017-2019, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#include +#include + +#include "blupi.h" +#include "def.h" +#include "event.h" +#include "misc.h" +#include "pixmap.h" +#include "text.h" + +/** + * \brief Return the character offset for the sprite. + * + * \param[in] c - The character (incremented if 0xC3 or 0xC4 or 0xC5 UTF-8). + * \returns the offset. + */ +static Uint8 +GetOffset (const char *& c) +{ + /* clang-format off */ + static const unsigned char table_c3[] = { + /* ü à â é è ë ê ï */ + 0xBC, 0xA0, 0xA2, 0xA9, 0xA8, 0xAB, 0xAA, 0xAF, + /* î ô ù û ä ö ç ò */ + 0xAE, 0xB4, 0xB9, 0xBB, 0xA4, 0xB6, 0xA7, 0xB2, + /* ì ó Ç Ö Ü õ ã */ + 0xAC, 0xB3, 0x87, 0x96, 0x9C, 0xB5, 0xA3 + }; + + static const unsigned char table_c4[] = { + /* ę ć ą Ğ ğ İ ı */ + 0x99, 0x87, 0x85, 0x9E, 0x9F, 0xB0, 0xB1, + }; + + static const unsigned char table_c5[] = { + /* ń ź ż ł ś Ş ş */ + 0x84, 0xBA, 0xBC, 0x82, 0x9B, 0x9E, 0x9F, + }; + + static const unsigned char table_d7[] = { + /*a ז ו ה ד ג ב א */ + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + /*a מ ל ך כ י ט ח */ + 0x97, 0x98, 0x99, 0x9B, 0x9A, 0x9C, 0x9E, + /*a ף פ ע ס ן נ ם */ + 0x9D, 0xA0, 0x9F, 0xA1, 0xA2, 0xA4, 0xA3, + /*a ת ש ר ק ץ צ */ + 0xA6, 0xA5, 0xA7, 0xA8, 0xA9, 0xAA, + }; + /* clang-format on */ + + int offset = 0; + int inc = 0; + size_t size = 0; + const unsigned char * table = nullptr; + + switch (static_cast (*c)) + { + case 0xC3: + offset = 128; + table = table_c3; + size = countof (table_c3); + inc = 1; + break; + case 0xC4: + offset = 128 + 32; + table = table_c4; + size = countof (table_c4); + inc = 1; + break; + case 0xC5: + offset = 128 + 64; + table = table_c5; + size = countof (table_c5); + inc = 1; + break; + case 0xD7: + offset = 128 + 96; + table = table_d7; + size = countof (table_d7); + inc = 1; + break; + } + + for (size_t i = 0; i < size; ++i) + if (static_cast (*(c + inc)) == table[i]) + return offset + i; + + if (*(c + inc) < 0) + return 1; // square + + return *(c + inc); +} + +/** + * \brief Return the character length. + * + * \param[in] c - The character (can be incremented). + * \param[in] font - The font used (little or normal). + * \returns the length. + */ +Uint8 +GetCharWidth (const char *& c, Sint32 font) +{ + // clang-format off + static const Uint8 table_width[] = + { + 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, + 5, 6, 9, 13, 11, 12, 12, 6, 6, 6, 12, 12, 5, 9, 6, 9, + 8, 8, 9, 9, 8, 9, 8, 8, 9, 9, 6, 6, 8, 9, 10, 11, + 12, 8, 9, 9, 9, 8, 8, 8, 9, 4, 8, 9, 8, 10, 9, 9, + 8, 9, 8, 9, 10, 8, 9, 11, 9, 8, 10, 7, 10, 7, 13, 13, + 9, 9, 8, 8, 8, 8, 6, 8, 8, 4, 6, 8, 4, 12, 8, 8, + 8, 8, 7, 6, 7, 8, 8, 10, 8, 8, 7, 6, 6, 6, 10, 0, + 8, 9, 9, 8, 8, 8, 8, 5, 5, 8, 8, 8, 9, 8, 8, 8, + 5, 8, 9, 9, 8, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 9, 8, 8, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 7, 6, 7, 9, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 9, 8, 8, 9, 5, 7, 9, 10, 6, 8, 8, 9, 10, 9, 6, + 7, 9, 9, 8, 9, 9, 10, 9, 8, 12, 10, 0, 0, 0, 0, 0, + }; + + static const Uint8 table_width_little[] = + { + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, + 3, 3, 5, 8, 5, 11, 9, 3, 4, 4, 6, 6, 3, 4, 3, 6, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 7, 6, 7, 6, + 9, 8, 6, 7, 7, 5, 5, 8, 7, 2, 4, 7, 5, 10, 7, 8, + 6, 8, 7, 6, 6, 6, 8, 12, 7, 6, 6, 3, 5, 3, 6, 8, + 4, 6, 6, 6, 6, 6, 4, 6, 6, 2, 3, 5, 2, 10, 6, 6, + 6, 6, 3, 5, 3, 6, 6, 8, 6, 6, 5, 4, 6, 4, 7, 0, + 7, 6, 6, 6, 6, 6, 6, 3, 3, 6, 6, 6, 6, 6, 6, 6, + 3, 6, 7, 8, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 5, 7, 8, 6, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 5, 5, 4, 5, 6, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 7, 5, 6, 7, 2, 4, 7, 7, 3, 5, 7, 6, 7, 7, 4, + 3, 7, 7, 7, 8, 7, 6, 7, 7, 9, 8, 0, 0, 0, 0, 0, + }; + // clang-format on + + if (font == FONTLITTLE) + return table_width_little[GetOffset (c)]; + return table_width[GetOffset (c)] - 1; +} + +/** + * \brief Draw a text in a pixmap to a specific position. + * + * \param[in] pPixmap - The pixmap where it must be drawn. + * \param[in] pos - The coordinates for the text. + * \param[in] pText - The text. + * \param[in] font - The font style (little or normal). + * \param[in] slope - Text slope. + */ +void +DrawText ( + CPixmap * pPixmap, Point pos, const char * pText, Sint32 font, Sint32 slope) +{ + Sint32 rank; + bool isLatin = false; + int numberSize = 0; + const char * it = nullptr; + int skip = 0; + Sint32 start = pos.y; + Sint32 rel = 0; + + auto useD7 = strchr (pText, 0xD7) != nullptr; + auto isRightReading = useD7 && IsRightReading (); + auto length = strlen (pText); + + if (length >= 1 && !useD7 && IsRightReading ()) + pos.x -= GetTextWidth (pText, font); + + while (*pText != '\0' || skip) + { + if (isRightReading && numberSize == 0) + { + const auto test = [](const char * text) -> bool { + return *text > ' ' && *text <= '~'; + }; + it = pText; + isLatin = test (pText); + if (isLatin) + { + while (test (pText)) + ++pText; + + numberSize = pText - it; + skip = numberSize - 1; + } + } + + if (numberSize) + { + pText = it + numberSize - 1; + numberSize--; + } + + rank = GetOffset (pText); + + if (isRightReading) + { + if (rank == '(') + rank = ')'; + else if (rank == ')') + rank = '('; + } + + auto inc = rank > 127; + auto lg = GetCharWidth (pText, font); + + if (isRightReading) + pos.x += -lg; + + rel += lg; + if (slope) + pos.y = start + rel / slope; + + if (font != FONTLITTLE) + { + rank += 256 * font; + pPixmap->DrawIcon (-1, CHTEXT, rank, pos); + } + else + pPixmap->DrawIcon (-1, CHLITTLE, rank, pos); + + if (!isRightReading) + pos.x += lg; + + if (!numberSize && skip > 0) + { + pText += skip; + skip = 0; + } + + if (inc) + pText++; + pText++; + } +} + +// Affiche un pavé de texte. +// Une ligne vide est affichée avec un demi interligne ! +// Si part != -1, n'affiche que les lignes qui commencent +// par "n|", avec n=part. + +void +DrawTextRect ( + CPixmap * pPixmap, Point pos, char * pText, Sint32 pente, Sint32 font, + Sint32 part) +{ + char text[100]; + char * pDest; + Sint32 itl; + + if (font == FONTLITTLE) + itl = DIMLITTLEY; + else + itl = DIMTEXTY; + + while (*pText != 0) + { + pDest = text; + while (*pText != 0 && *pText != '\r' && *pText != '\n') + *pDest++ = *pText++; + *pDest = 0; + if (*pText == '\r') + pText++; // saute '\r' + if (*pText == '\n') + pText++; // saute '\n' + + pDest = text; + if (text[0] != 0 && text[1] == '|') // commence par "n|" ? + { + if (part != -1 && part != text[0] - '0') + continue; + pDest += 2; // saute "n|" + } + else + { + if (part != -1) + continue; + } + + DrawText (pPixmap, pos, pDest, font, pente); + + if (pDest[0] == 0) // ligne vide ? + { + pos.y += itl / 2; // descend de 1/2 ligne + } + else + { + pos.y += itl; // passe à la ligne suivante + } + } +} + +// Affiche un texte centré pouvant éventuellement +// contenir plusieurs lignes séparées par des '\n'. + +void +DrawTextCenter (CPixmap * pPixmap, Point pos, const char * pText, Sint32 font) +{ + char text[100]; + char * pDest; + Sint32 itl; + Point start; + auto isRightReading = IsRightReading (); + + if (font == FONTLITTLE) + itl = DIMLITTLEY; + else + itl = DIMTEXTY; + + while (*pText != 0) + { + pDest = text; + while (*pText != 0 && *pText != '\r' && *pText != '\n') + *pDest++ = *pText++; + *pDest = 0; + if (*pText == '\r') + pText++; // saute '\r' + if (*pText == '\n') + pText++; // saute '\n' + + pDest = text; + start.x = + pos.x + + (isRightReading ? GetTextWidth (pDest) : -GetTextWidth (pDest)) / 2; + start.y = pos.y; + DrawText (pPixmap, start, pDest, font); + + if (pDest[0] == 0) // ligne vide ? + { + pos.y += itl / 2; // descend de 1/2 ligne + } + else + { + pos.y += itl; // passe à la ligne suivante + } + } +} + +// Retourne la hauteur d'un texte. + +Sint32 +GetTextHeight (char * pText, Sint32 font, Sint32 part) +{ + char text[100]; + char * pDest; + Sint32 itl; + Sint32 h = 0; + + if (font == FONTLITTLE) + itl = DIMLITTLEY; + else + itl = DIMTEXTY; + + while (*pText != 0) + { + pDest = text; + while (*pText != 0 && *pText != '\r' && *pText != '\n') + *pDest++ = *pText++; + *pDest = 0; + if (*pText == '\r') + pText++; // saute '\r' + if (*pText == '\n') + pText++; // saute '\n' + + pDest = text; + if (text[0] != 0 && text[1] == '|') // commence par "n|" ? + { + if (part != -1 && part != text[0] - '0') + continue; + pDest += 2; // saute "n|" + } + else + { + if (part != -1) + continue; + } + + if (pDest[0] == 0) // ligne vide ? + { + h += itl / 2; // descend de 1/2 ligne + } + else + { + h += itl; // passe à la ligne suivante + } + } + + return h; +} + +// Retourne la longueur d'un texte. + +Sint32 +GetTextWidth (const char * pText, Sint32 font) +{ + Sint32 width = 0; + + while (*pText != 0) + { + auto rank = GetOffset (pText); + auto inc = rank > 127; + + width += GetCharWidth (pText, font); + + if (inc) + pText++; + pText++; + } + + return width; +} + +// Retourne la longueur d'un grand chiffre. + +void +GetBignumInfo (Sint32 num, Sint32 & start, Sint32 & lg) +{ + static Sint32 table[11] = {0, 53, 87, 133, 164, 217, 253, 297, 340, 382, 426}; + + start = table[num]; + lg = table[num + 1] - table[num]; +} + +// Affiche un grand nombre. + +void +DrawBignum (CPixmap * pPixmap, Point pos, Sint32 num) +{ + char string[10]; + Sint32 i = 0; + Sint32 start, lg; + Rect rect; + + snprintf (string, sizeof (string), "%d", num); + + rect.top = 0; + rect.bottom = 52; + while (string[i] != 0) + { + GetBignumInfo (string[i] - '0', start, lg); + + rect.left = start; + rect.right = start + lg; + pPixmap->DrawPart (-1, CHBIGNUM, pos, rect); + pos.x += lg + 4; + + i++; + } +} + +// Retourne la longueur d'un grand nombre. + +Sint32 +GetBignumWidth (Sint32 num) +{ + char string[10]; + Sint32 i = 0; + Sint32 start, lg; + Sint32 width = -4; + + snprintf (string, sizeof (string), "%d", num); + + while (string[i] != 0) + { + GetBignumInfo (string[i] - '0', start, lg); + width += lg + 4; + i++; + } + + return width; +} diff --git a/src/text.h b/src/text.h new file mode 100644 index 0000000..f29cca3 --- /dev/null +++ b/src/text.h @@ -0,0 +1,44 @@ +/* + * This file is part of the planetblupi source code + * Copyright (C) 1997, Daniel Roux & EPSITEC SA + * Copyright (C) 2017, Mathieu Schroeter + * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +// clang-format off +#define FONTWHITE 0 +#define FONTRED 1 +#define FONTSLIM 2 +#define FONTLITTLE 10 +// clang-format on + +void DrawText ( + CPixmap * pPixmap, Point pos, const char * pText, Sint32 font = 0, + Sint32 slope = 0); + +void DrawTextRect ( + CPixmap * pPixmap, Point pos, char * pText, Sint32 pente, Sint32 font = 0, + Sint32 part = -1); + +void DrawTextCenter ( + CPixmap * pPixmap, Point pos, const char * pText, Sint32 font = 0); + +Sint32 GetTextHeight (char * pText, Sint32 font = 0, Sint32 part = -1); +Sint32 GetTextWidth (const char * pText, Sint32 font = 0); +void DrawBignum (CPixmap * pPixmap, Point pos, Sint32 num); +Sint32 GetBignumWidth (Sint32 num); -- cgit v1.2.3