diff --git a/CMakeLists.txt b/CMakeLists.txt index e09dd28c2312d..941dad92f708f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ option(TILES "Build graphical tileset version." "OFF") option(CURSES "Build curses version." "ON") option(SOUND "Support for in-game sounds & music." "OFF") option(BACKTRACE "Support for printing stack backtraces on crash" "ON") +option(LIBBACKTRACE "Print backtrace with libbacktrace." "OFF") option(USE_HOME_DIR "Use user's home directory for save files." "ON") option(LOCALIZE "Support for language localizations. Also enable UTF support." "ON") option(LANGUAGES "Compile localization files for specified languages." "") @@ -323,6 +324,9 @@ ENDIF(SOUND) IF(BACKTRACE) ADD_DEFINITIONS(-DBACKTRACE) + IF(LIBBACKTRACE) + ADD_DEFINITIONS(-DLIBBACKTRACE) + ENDIF(LIBBACKTRACE) ENDIF(BACKTRACE) # Ok. Now create build and install recipes diff --git a/LICENSE.txt b/LICENSE.txt index 1f0b1564e7661..2f024ae9588eb 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -9,3 +9,35 @@ CATCH unit-test framework (tests/catch/catch.hpp) is licensed under the Boost So PLF List and PLF Colony (src/list.h, src/colony.h) are licensed under the zLib license (https://www.zlib.net/zlib_license.html). getpost (tools/json_tools/format/getpost.h) is licensed under the MIT license, see file for text of license. + +libbacktrace is licensed under a BSD license (https://github.com/ianlancetaylor/libbacktrace/blob/master/LICENSE). The full license text is as follows: + +# Copyright (C) 2012-2016 Free Software Foundation, Inc. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: + +# (1) Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. + +# (2) Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. + +# (3) The name of the author may not be used to +# endorse or promote products derived from this software without +# specific prior written permission. + +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile index a99c7e495562e..66cda1b6d6318 100644 --- a/Makefile +++ b/Makefile @@ -40,6 +40,8 @@ # make LOCALIZE=0 # Disable backtrace support, not available on all platforms # make BACKTRACE=0 +# Use libbacktrace. Only has effect if BACKTRACE=1. (currently only for MinGW builds) +# make LIBBACKTRACE=1 # Compile localization files for specified languages # make localization LANGUAGES="[ lang_id_2][ ...]" # (for example: make LANGUAGES="zh_CN zh_TW" for Chinese) @@ -171,6 +173,14 @@ ifndef BACKTRACE BACKTRACE = 1 endif endif +ifdef BACKTRACE + # Also enable libbacktrace on cross-compilation to Windows + ifndef LIBBACKTRACE + ifneq (,$(findstring mingw32,$(CROSS))) + LIBBACKTRACE = 1 + endif + endif +endif ifeq ($(RUNTESTS), 1) TESTS = tests @@ -185,7 +195,7 @@ W32ODIR = $(BUILD_PREFIX)objwin W32ODIRTILES = $(W32ODIR)/tiles ifdef AUTO_BUILD_PREFIX - BUILD_PREFIX = $(if $(RELEASE),release-)$(if $(DEBUG_SYMBOLS),symbol-)$(if $(TILES),tiles-)$(if $(SOUND),sound-)$(if $(LOCALIZE),local-)$(if $(BACKTRACE),back-)$(if $(SANITIZE),sanitize-)$(if $(MAPSIZE),map-$(MAPSIZE)-)$(if $(USE_XDG_DIR),xdg-)$(if $(USE_HOME_DIR),home-)$(if $(DYNAMIC_LINKING),dynamic-)$(if $(MSYS2),msys2-) + BUILD_PREFIX = $(if $(RELEASE),release-)$(if $(DEBUG_SYMBOLS),symbol-)$(if $(TILES),tiles-)$(if $(SOUND),sound-)$(if $(LOCALIZE),local-)$(if $(BACKTRACE),back-$(if $(LIBBACKTRACE),libbacktrace-))$(if $(SANITIZE),sanitize-)$(if $(MAPSIZE),map-$(MAPSIZE)-)$(if $(USE_XDG_DIR),xdg-)$(if $(USE_HOME_DIR),home-)$(if $(DYNAMIC_LINKING),dynamic-)$(if $(MSYS2),msys2-) export BUILD_PREFIX endif @@ -340,7 +350,7 @@ endif CXXFLAGS += $(WARNINGS) $(DEBUG) $(DEBUGSYMS) $(PROFILE) $(OTHERS) -MMD -MP TOOL_CXXFLAGS = -DCATA_IN_TOOL -BINDIST_EXTRAS += README.md data doc +BINDIST_EXTRAS += README.md data doc LICENSE.txt BINDIST = $(BUILD_PREFIX)cataclysmdda-$(VERSION).tar.gz W32BINDIST = $(BUILD_PREFIX)cataclysmdda-$(VERSION).zip BINDIST_CMD = tar --transform=s@^$(BINDIST_DIR)@cataclysmdda-$(VERSION)@ -czvf $(BINDIST) $(BINDIST_DIR) @@ -666,11 +676,17 @@ ifeq ($(TARGETSYSTEM),WINDOWS) LDFLAGS += -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lversion ifeq ($(BACKTRACE),1) LDFLAGS += -ldbghelp + ifeq ($(LIBBACKTRACE),1) + LDFLAGS += -lbacktrace + endif endif endif ifeq ($(BACKTRACE),1) DEFINES += -DBACKTRACE + ifeq ($(LIBBACKTRACE),1) + DEFINES += -DLIBBACKTRACE + endif endif ifeq ($(LOCALIZE),1) diff --git a/build-scripts/libbacktrace-i686-w64-mingw32-sha256 b/build-scripts/libbacktrace-i686-w64-mingw32-sha256 new file mode 100644 index 0000000000000..fd72cd8459578 --- /dev/null +++ b/build-scripts/libbacktrace-i686-w64-mingw32-sha256 @@ -0,0 +1 @@ +52811183c904305ddfa28d4b2236cc14da5293cd4d038d02b57d53dc18701502 *libbacktrace-i686-w64-mingw32.tar.gz diff --git a/build-scripts/requirements.sh b/build-scripts/requirements.sh index 5470c7761d499..0d24a13768029 100644 --- a/build-scripts/requirements.sh +++ b/build-scripts/requirements.sh @@ -53,6 +53,13 @@ if [ -n "${MXE_TARGET}" ]; then # Need to overwrite CXX to make the Makefile $CROSS logic work right. export CXX="$COMPILER" export CCACHE=1 + + curl -L -o libbacktrace-i686-w64-mingw32.tar.gz https://github.com/Qrox/libbacktrace/releases/download/2020-01-03/libbacktrace-i686-w64-mingw32.tar.gz + if ! shasum -a 256 -c ./build-scripts/libbacktrace-i686-w64-mingw32-sha256; then + echo "Checksum failed for libbacktrace-i686-w64-mingw32.tar.gz" + exit 1 + fi + sudo tar -xzf libbacktrace-i686-w64-mingw32.tar.gz --exclude=LICENSE -C ${MXE_DIR}/../${PLATFORM} fi if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then diff --git a/data/json/itemgroups/food.json b/data/json/itemgroups/food.json index ee72007a63973..4b86e646dddfd 100644 --- a/data/json/itemgroups/food.json +++ b/data/json/itemgroups/food.json @@ -851,5 +851,45 @@ [ "eggnog_spiked", 5 ], [ "drink_martini", 10 ] ] + }, + { + "id": "barbecue", + "type": "item_group", + "items": [ + [ "beer", 15 ], + [ "meat", 65 ], + [ "glazed_tenderloin", 55 ], + [ "fish", 10 ], + [ "fish_smoked", 5 ], + [ "meat_smoked", 60 ], + [ "sausage", 35 ], + [ "bratwurst_sausage", 30 ], + [ "hotdogs_frozen", 65 ], + [ "hotdogs_cooked", 65 ], + [ "chilidogs", 30 ], + [ "currywurst", 15 ], + [ "lettuce", 45 ], + [ "tomato", 45 ], + [ "onion", 30 ], + [ "chili_pepper", 30 ], + [ "corn", 20 ], + [ "irradiated_lettuce", 20 ], + [ "irradiated_tomato", 20 ], + [ "irradiated_onion", 5 ], + [ "irradiated_corn", 10 ], + [ "bacon", 20 ], + [ "potato_baked", 15 ], + [ "bread", 40 ], + [ "ketchup", 80 ], + [ "mustard", 75 ], + { "item": "pickle", "prob": 20, "charges": 6, "container-item": "jar_glass_sealed" }, + [ "pickle", 20 ], + [ "cheeseburger", 30 ], + [ "hamburger", 70 ], + [ "cheese", 45 ], + [ "ceramic_plate", 30 ], + [ "knife_steak", 45 ], + [ "tongs", 60 ] + ] } ] diff --git a/data/json/itemgroups/item_groups.json b/data/json/itemgroups/item_groups.json index c0f4be4ef32d8..bb839f90f96c2 100644 --- a/data/json/itemgroups/item_groups.json +++ b/data/json/itemgroups/item_groups.json @@ -491,7 +491,7 @@ { "type": "item_group", "id": "fridge", - "//": "This is a terrible item group and should be phased out. See SUS_fridge for a more modern take on things.", + "//": "This is a terrible item group and should be phased out. See SUS_fridge in SUS - > domestic.json for a more modern take on things.", "items": [ [ "water_clean", 90 ], [ "water_mineral", 10 ], @@ -3102,7 +3102,7 @@ "type": "item_group", "items": [ [ "citrine", 50 ], - [ "diamond", 50 ], + [ "diamond", 100 ], [ "emerald", 50 ], [ "peridot", 50 ], [ "amethyst", 50 ], @@ -3111,7 +3111,7 @@ [ "blue_topaz", 50 ], [ "tourmaline", 50 ], [ "alexandrite", 50 ], - [ "pearl", 50 ], + [ "pearl", 100 ], [ "opal", 50 ], [ "ruby", 50 ], [ "garnet", 50 ] diff --git a/data/json/items/corpses.json b/data/json/items/corpses/corpses.json similarity index 92% rename from data/json/items/corpses.json rename to data/json/items/corpses/corpses.json index fe7f6a936aa4e..0e8ffc54b559e 100644 --- a/data/json/items/corpses.json +++ b/data/json/items/corpses/corpses.json @@ -54,8 +54,8 @@ "name": "corpse", "description": "A dead body of a young woman.", "looks_like": "corpse", - "volume": "40000 ml", - "weight": "52000 g", + "volume": "40 L", + "weight": "52 kg", "material": "hflesh" }, { @@ -65,6 +65,8 @@ "name": "corpse", "description": "A dead body of a little boy.", "looks_like": "corpse", + "volume": "30 L", + "weight": "30 kg", "material": "hflesh" }, { @@ -74,6 +76,8 @@ "name": "corpse", "description": "A dead body of a little girl.", "looks_like": "corpse", + "volume": "30 L", + "weight": "30 kg", "material": "hflesh" }, { @@ -83,8 +87,8 @@ "name": "corpse", "description": "The dead body of a small child. Their corpse bears a calm facial expression, as if they died instantly.", "looks_like": "corpse", - "volume": "30000 ml", - "weight": "40750 g", + "volume": "30 L", + "weight": "30 kg", "material": "hflesh" }, { @@ -94,8 +98,8 @@ "name": "corpse", "description": "The dead body of a child, riddled by bullets to the extent that you can no longer tell their gender.", "looks_like": "corpse", - "volume": "30000 ml", - "weight": "40750 g", + "volume": "30 L", + "weight": "30 kg", "material": "hflesh" }, { @@ -106,8 +110,8 @@ "description": "A dead body of an old woman. Both of her earlobes are torn, several fingers on her hands have been chopped off, and several teeth have been knocked out.", "//": "Implied that someone hacked off her body parts for jewelry.", "looks_like": "corpse", - "volume": "40000 ml", - "weight": "52000 g", + "volume": "40 L", + "weight": "52 kg", "material": "hflesh" }, { @@ -153,8 +157,8 @@ "name": "corpse", "description": "The dead body of a person. Their forehead bears a large bullet entrance wound. An even larger exit wound is present on the back of their head.", "looks_like": "corpse", - "volume": "40000 ml", - "weight": "52000 g", + "volume": "40 L", + "weight": "52 kg", "material": "hflesh" }, { @@ -164,8 +168,8 @@ "name": "corpse", "description": "The upper half of a dead body, as if torn apart with enormous force. Some organs are hanging out.", "looks_like": "corpse", - "volume": "30000 ml", - "weight": "40000 g", + "volume": "30 L", + "weight": "40 kg", "material": "hflesh" }, { @@ -175,8 +179,8 @@ "name": "corpse", "description": "A half-decapitated dead body. It is unclear what could have caused such a wound.", "looks_like": "corpse", - "volume": "57000 ml", - "weight": "78000 g", + "volume": "57 L", + "weight": "78 kg", "material": "hflesh" } ] diff --git a/data/json/mapgen/house/house_library.json b/data/json/mapgen/house/house_library.json index 495ff05f76019..3440171434f8c 100644 --- a/data/json/mapgen/house/house_library.json +++ b/data/json/mapgen/house/house_library.json @@ -2,117 +2,56 @@ { "type": "mapgen", "method": "json", - "om_terrain": [ "house" ], - "weight": 100, + "om_terrain": [ "house_library" ], + "weight": 200, "object": { "fill_ter": "t_floor", "rows": [ - "...............P........", - ".--vv--;--vv-----------.", - ".|Y Y|ooooo R|.", - ".| |o v.", - ".| nn |o v.", - ".| h nnh | K r|.", - ".| nn 0|0 r|.", - ".v nnh | Kc r|.", - ".v nn |o v.", - ".| h C|o v.", - ".| h C|oooo R|.", - ".|h C|----+---|.", - ".|------ ----- K |.", - ".|f c| ????? K|.", - ".vO c| ? v.", - ".vC + n ? v.", - ".|S | |.", - ".|--+------+------+---|.", - ".|B | | |.", - ".|B + | v.", - ".v S| @@ | @@ v.", - ".|t | @@d | @@ d|.", - ".---------vv-----------.", - "........................" - ], - "set": [ - { "point": "terrain", "id": "t_dirt", "x": [ 0, 0 ], "y": [ 0, 23 ], "repeat": [ 5, 10 ] }, - { "point": "terrain", "id": "t_dirt", "x": [ 23, 23 ], "y": [ 0, 23 ], "repeat": [ 5, 10 ] }, - { "point": "terrain", "id": "t_dirt", "x": [ 0, 23 ], "y": [ 23, 23 ], "repeat": [ 5, 8 ] }, - { "point": "terrain", "id": "t_dirt", "x": [ 0, 14 ], "y": [ 0, 0 ], "repeat": [ 5, 8 ] } + "......---......p........", + ".##oo##*##oo###########.", + ".#y h L y|RRRRRvyR#.", + ".# |R Ho.", + ".#r ff |R Ho.", + ".#rh ffh | EE r#.", + ".#r hff a|a ssT r#^", + ".o ffh | EE r#.", + ".oc h |R Ho.", + ".#||||||| |||R Ho.", + ".#y666 |>|RRRR R#.", + ".#7 | |||||+|||#.", + ".#4 JA T#.", + ".#O J A HHHHHs E#.", + ".o1 JA H ll so.", + ".o5 H Eo.", + ".#23 Y xxx #.", + ".#||+||||||+||||||+|||#.", + ".#B!!Q|TE ydd|sE II#.", + ".#B!!!+ |y ho.", + ".o!!!S|Ih @@ b| @@ o.", + ".#t!!8|I @@s D|D @@ d#.", + ".#########oo###########.", + "............^..........." ], + "palettes": [ "standard_domestic_palette" ], "terrain": { - "+": "t_door_c", - "-": "t_wall", - ".": "t_grass", - "0": "t_floor", - ";": "t_door_locked", - "?": "t_floor", - "@": "t_floor", - "B": "t_floor", - "C": "t_floor", - "Y": "t_floor", - "R": "t_floor", - "O": "t_floor", - "P": "t_grass", - "S": "t_floor", - "c": "t_floor", - "d": "t_floor", - "f": "t_floor", - "h": "t_floor", - "k": "t_floor", - "n": "t_floor", - "o": "t_floor", - "r": "t_floor", - "v": "t_window_domestic", - "|": "t_wall" - }, - "furniture": { - "0": "f_fireplace", - "?": "f_sofa", - "@": "f_bed", - "Y": "f_rack_coat", - "R": "f_stool", - "B": "f_bathtub", - "C": "f_cupboard", - "K": "f_armchair", - "O": "f_oven", - "P": "f_mailbox", - "S": "f_sink", - "c": "f_counter", - "d": "f_dresser", - "f": "f_fridge", - "h": "f_chair", - "n": "f_table", - "o": "f_bookcase", - "r": "f_rack" + "%": [ "t_region_shrub", "t_region_shrub_fruit", "t_region_shrub_decorative" ], + ":": [ [ "t_region_tree_fruit", 2 ], [ "t_region_tree_nut", 2 ], "t_region_tree_shade" ], + "&": "t_region_groundcover_urban", + "$": "t_railing_h", + "_": "t_pavement", + "G": "t_concrete", + "K": "t_concrete", + "~": "t_concrete", + "j": "t_concrete", + "!": "t_linoleum_gray", + "8": "t_linoleum_gray", + "t": "t_linoleum_gray", + "9": "t_linoleum_gray", + "S": "t_linoleum_gray", + "Q": "t_linoleum_gray", + "[": "t_door_glass_c" }, - "toilets": { "t": { } }, - "items": { - "Y": { "item": "coat_rack", "chance": 30, "repeat": [ 1, 4 ] }, - "P": { "item": "mail", "chance": 30, "repeat": [ 2, 5 ] } - }, - "place_loot": [ - { "group": "bed", "x": [ 10, 11 ], "y": [ 20, 21 ], "chance": 90, "repeat": [ 1, 3 ] }, - { "group": "bed", "x": [ 18, 19 ], "y": [ 20, 21 ], "chance": 90, "repeat": [ 1, 3 ] }, - { "group": "bedroom", "x": [ 7, 21 ], "y": [ 18, 21 ], "chance": 80, "repeat": [ 1, 6 ] }, - { "group": "livingroom", "x": [ 8, 21 ], "y": [ 13, 16 ], "chance": 85, "repeat": [ 1, 5 ] }, - { "group": "guns_pistol_common", "x": [ 12, 12 ], "y": [ 21, 21 ], "chance": 5, "ammo": 90, "magazine": 100 }, - { "group": "dresser", "x": [ 21, 21 ], "y": [ 21, 21 ], "chance": 85, "repeat": [ 1, 4 ] }, - { "group": "dresser", "x": [ 12, 12 ], "y": [ 21, 21 ], "chance": 85, "repeat": [ 1, 3 ] }, - { "group": "kitchen", "x": [ 2, 6 ], "y": [ 13, 16 ], "chance": 70, "repeat": [ 1, 3 ] }, - { "group": "kitchen", "x": [ 2, 2 ], "y": [ 15, 15 ], "chance": 90, "repeat": [ 1, 2 ] }, - { "group": "fridge", "x": [ 2, 2 ], "y": [ 13, 13 ], "chance": 80, "repeat": [ 1, 4 ] }, - { "group": "dining", "x": [ 6, 7 ], "y": [ 4, 8 ], "chance": 80, "repeat": [ 1, 4 ] }, - { "group": "oven", "x": [ 2, 2 ], "y": [ 14, 14 ], "chance": 75, "repeat": [ 1, 3 ] }, - { "group": "softdrugs", "x": [ 2, 4 ], "y": [ 18, 21 ], "chance": 75, "repeat": [ 1, 3 ] }, - { "group": "cleaning", "x": [ 2, 4 ], "y": [ 18, 21 ], "chance": 90, "repeat": [ 1, 2 ] }, - { "group": "homebooks", "x": [ 15, 18 ], "y": [ 2, 2 ], "chance": 75, "repeat": [ 1, 3 ] }, - { "group": "novels", "x": [ 14, 14 ], "y": [ 2, 4 ], "chance": 90, "repeat": [ 1, 4 ] }, - { "group": "textbooks", "x": [ 14, 14 ], "y": [ 2, 4 ], "chance": 50, "repeat": [ 1, 2 ] }, - { "group": "novels", "x": [ 14, 14 ], "y": [ 8, 10 ], "chance": 90, "repeat": [ 1, 4 ] }, - { "group": "textbooks", "x": [ 14, 14 ], "y": [ 8, 10 ], "chance": 50, "repeat": [ 1, 2 ] }, - { "group": "homebooks", "x": [ 15, 17 ], "y": [ 10, 10 ], "chance": 75, "repeat": [ 1, 3 ] }, - { "group": "homebooks", "x": [ 18, 18 ], "y": [ 7, 7 ], "chance": 40, "repeat": [ 1, 2 ] }, - { "group": "alcohol", "x": [ 21, 21 ], "y": [ 5, 7 ], "chance": 75, "repeat": [ 1, 2 ] } - ], + "furniture": { "&": "f_region_flower" }, "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": [ 2, 21 ], "y": [ 2, 21 ], "chance": 2 } ] } } diff --git a/data/json/mapgen/house/house_modern_lx.json b/data/json/mapgen/house/house_modern_lx.json index 3c1a5e1943e74..1647255f21199 100644 --- a/data/json/mapgen/house/house_modern_lx.json +++ b/data/json/mapgen/house/house_modern_lx.json @@ -2,114 +2,100 @@ { "type": "mapgen", "method": "json", - "om_terrain": [ "house" ], + "om_terrain": [ "house_modern_1" ], "weight": 200, "object": { "fill_ter": "t_floor", "rows": [ - "...........#.....s.....#", - "...........#....Zs.....#", - "...........#.....s.....#", - "...........#.....s.....#", - "...........RRRVVR+RVVRRR", - "...........R???? ? 0R", - ".~~~~~~~~~~V ? n V", - ".~~~~~~~~~~V ? ? V", - ".~~~~~~~~~~V???? ???V", - ".~~~~~~~~~~R V", - ".~~ ~~Rr V", - ".RRRR[RRRRRR R", - ".Ro oRP hhhhhh R", - ".V ppp oR nnnnnn R", - ".V ppp R RRRRRRRRRRRR", - ".V R + R.", - ".R n Rr c V.", - ".RoK hK ????cRr c R.", - ".RRRRRRR++RRRRRRR V.", - ".R d@@ kkkPROffccR.", - ".R @@ h RRRRRRR.", - ".R + tS BR.", - ".RRRVVVVVVVVVVRRR BR.", - "................RRVRVRR." + "...........%....&-&....%", + "........:..%....p-&..:.%", + "..:........%.:..&-&....%", + ".......:...%....&-&....%", + "...:.......###$$#*#$$###", + ".....jjj...#HHHHL H a#", + ".~~~~~~~~~~$ H l $", + ".~~~~~~~~~~$ H $", + ".~~~~~~~~~~# H $", + ".~~~~~~~~~~#HHHH sHHH$", + ".~~______~^#M $", + ".####[###### #", + ".#R R#y AAAAAA #", + ".$ eee R# ffffff #", + ".$ eee # ############", + ".$ # + y#^", + ".# l #6 J y$.", + ".#RE hE sHHH#>#6 J 7#.", + ".#######++#######4 3$.", + ".#T d@@ bIIIy#1FO52#.", + ".#D @@ h #######.", + ".#E +!tS!B#.", + ".###$$$$$$$$$$###8!!!B#.", + "................##$#$##." ], + "palettes": [ "standard_domestic_palette" ], "terrain": { - "#": "t_shrub", - "+": "t_door_metal_c", - ".": "t_grass", - "Z": "t_grass", - "0": "t_floor", - "?": "t_floor", - "@": "t_floor", - "B": "t_floor", - "D": "t_floor", - "K": "t_floor", - "O": "t_floor", - "P": "t_floor", - "R": "t_rock", - "S": "t_floor", - "V": "t_wall_glass", - "[": "t_door_glass_c", - "c": "t_floor", - "d": "t_floor", - "f": "t_floor", - "h": "t_floor", - "k": "t_floor", - "n": "t_floor", - "o": "t_floor", - "p": "t_floor", - "r": "t_floor", - "s": "t_sidewalk", - "~": "t_water_sh" + "%": [ "t_region_shrub", "t_region_shrub_fruit", "t_region_shrub_decorative" ], + ":": [ [ "t_region_tree_fruit", 2 ], [ "t_region_tree_nut", 2 ], "t_region_tree_shade" ], + "&": "t_region_groundcover_urban", + "j": "t_region_groundcover_urban", + "#": "t_rock_wall", + "_": "t_concrete", + "~": "t_water_pool_shallow_outdoors", + "!": "t_linoleum_gray", + "8": "t_linoleum_gray", + "t": "t_linoleum_gray", + "B": "t_linoleum_gray", + "S": "t_linoleum_gray", + "Q": "t_linoleum_gray", + "$": "t_wall_glass", + "[": "t_door_glass_c" }, - "furniture": { - "0": "f_fireplace", - "?": "f_sofa", - "@": "f_bed", - "Z": "f_mailbox", - "B": "f_bathtub", - "D": "f_trashcan", - "K": "f_armchair", - "O": "f_oven", - "P": "f_indoor_plant", - "S": "f_sink", - "c": "f_counter", - "d": "f_dresser", - "f": "f_fridge", - "h": "f_chair", - "k": "f_desk", - "n": "f_table", - "o": "f_bookcase", - "p": "f_pool_table", - "r": "f_rack" - }, - "toilets": { "t": { } }, - "items": { "Z": { "item": "mail", "chance": 30, "repeat": [ 2, 5 ] } }, + "furniture": { "&": "f_region_flower" }, "place_loot": [ - { "group": "bed", "x": [ 5, 6 ], "y": [ 19, 20 ], "chance": 90, "repeat": [ 1, 4 ] }, - { "group": "bedroom", "x": [ 6, 7 ], "y": [ 19, 20 ], "chance": 80, "repeat": [ 1, 5 ] }, - { "group": "livingroom", "x": [ 12, 15 ], "y": [ 5, 8 ], "chance": 85, "repeat": [ 1, 2 ] }, - { "group": "livingroom", "x": [ 12, 15 ], "y": [ 19, 21 ], "chance": 85, "repeat": [ 1, 2 ] }, - { "group": "livingroom", "x": [ 9, 15 ], "y": [ 15, 17 ], "chance": 90, "repeat": [ 1, 3 ] }, - { "group": "dresser", "x": [ 4, 4 ], "y": [ 19, 19 ], "chance": 85, "repeat": [ 1, 4 ] }, - { "group": "fridge", "x": [ 18, 19 ], "y": [ 19, 19 ], "chance": 90, "repeat": [ 1, 6 ] }, - { "group": "kitchen", "x": [ 20, 21 ], "y": [ 19, 19 ], "chance": 60, "repeat": [ 1, 2 ] }, - { "group": "kitchen", "x": [ 17, 17 ], "y": [ 16, 16 ], "chance": 65, "repeat": [ 1, 2 ] }, - { "group": "kitchen", "x": [ 20, 20 ], "y": [ 16, 17 ], "chance": 50, "repeat": [ 1, 2 ] }, - { "group": "produce", "x": [ 17, 17 ], "y": [ 17, 17 ], "chance": 65, "repeat": [ 1, 2 ] }, - { "group": "novels", "x": [ 2, 2 ], "y": [ 17, 17 ], "chance": 85, "repeat": [ 1, 3 ] }, { "group": "textbooks", "x": [ 2, 2 ], "y": [ 17, 17 ], "chance": 40, "repeat": [ 1, 2 ] }, { "group": "alcohol", "x": [ 2, 2 ], "y": [ 12, 12 ], "chance": 65, "repeat": [ 1, 2 ] }, { "group": "alcohol", "x": [ 8, 8 ], "y": [ 12, 13 ], "chance": 80, "repeat": [ 1, 3 ] }, - { "group": "pool_table", "x": [ 4, 6 ], "y": [ 13, 14 ], "chance": 90, "repeat": [ 1, 6 ] }, - { "group": "office", "x": [ 11, 15 ], "y": [ 19, 21 ], "chance": 80, "repeat": [ 1, 3 ] }, - { "group": "oven", "x": [ 17, 17 ], "y": [ 19, 19 ], "chance": 75, "repeat": [ 1, 3 ] }, - { "group": "cleaning", "x": [ 17, 21 ], "y": [ 21, 22 ], "chance": 95, "repeat": [ 1, 2 ] }, - { "group": "softdrugs", "x": [ 17, 21 ], "y": [ 21, 22 ], "chance": 75, "repeat": [ 1, 3 ] }, { "item": "katana", "x": [ 12, 12 ], "y": [ 10, 10 ], "chance": 2 }, { "item": "katana_inferior", "x": [ 12, 12 ], "y": [ 10, 10 ], "chance": 8 }, { "item": "spiral_stone", "x": [ 12, 12 ], "y": [ 10, 10 ], "chance": 25 } ], "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": [ 2, 21 ], "y": [ 2, 21 ], "chance": 2 } ] } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "house_modern_1_roof", + "object": { + "fill_ter": "t_shingle_flat_roof", + "rows": [ + " ", + " ", + " ", + " ", + " |222222222223", + " |..........~3", + " |..oo...oo..3", + " |...........3", + " |...........3", + " |...........3", + " |...........3", + " |2222222225......X....3", + " |.....................3", + " |...oooo..............3", + " |...oooo.............53", + " |....................3 ", + " |....................3 ", + " |.................=..3 ", + " |....................3 ", + " |.................&..3 ", + " |....................3 ", + " |....................3 ", + " |--------------|.....3 ", + " |-----3 " + ], + "palettes": [ "roof_palette" ], + "terrain": { ".": "t_shingle_flat_roof" } + } } ] diff --git a/data/json/mapgen/house/house_patio.json b/data/json/mapgen/house/house_patio.json index 6063efbaf828b..c683c5c331cb1 100644 --- a/data/json/mapgen/house/house_patio.json +++ b/data/json/mapgen/house/house_patio.json @@ -1,165 +1,117 @@ [ - { - "id": "barbecue", - "type": "item_group", - "items": [ - [ "beer", 15 ], - [ "meat", 65 ], - [ "glazed_tenderloin", 55 ], - [ "fish", 10 ], - [ "fish_smoked", 5 ], - [ "meat_smoked", 60 ], - [ "sausage", 35 ], - [ "bratwurst_sausage", 30 ], - [ "hotdogs_frozen", 65 ], - [ "hotdogs_cooked", 65 ], - [ "chilidogs", 30 ], - [ "currywurst", 15 ], - [ "lettuce", 45 ], - [ "tomato", 45 ], - [ "onion", 30 ], - [ "chili_pepper", 30 ], - [ "corn", 20 ], - [ "irradiated_lettuce", 20 ], - [ "irradiated_tomato", 20 ], - [ "irradiated_onion", 5 ], - [ "irradiated_corn", 10 ], - [ "bacon", 20 ], - [ "potato_baked", 15 ], - [ "bread", 40 ], - [ "ketchup", 80 ], - [ "mustard", 75 ], - { "item": "pickle", "prob": 20, "charges": 6, "container-item": "jar_glass_sealed" }, - [ "pickle", 20 ], - [ "cheeseburger", 30 ], - [ "hamburger", 70 ], - [ "cheese", 45 ], - [ "ceramic_plate", 30 ], - [ "knife_steak", 45 ], - [ "tongs", 60 ] - ] - }, { "type": "mapgen", "method": "json", - "om_terrain": [ "house" ], - "weight": 300, + "om_terrain": [ "house_patio" ], + "weight": 200, "object": { "fill_ter": "t_floor", "rows": [ - ".sssssss...s............", - ".sssssssP--;v--vv--vv--.", - ".sssssss.|Y oo ????n|.", - ".sssssss.v v.", - ".sssssss.| -- nnn |.", - ".sssssss.| hnh D|.", - ".sssssss.v hnh v.", - ".sssssss.| c|.", - ".sssssss.| -----| c|.", - ".ssssssss; |U((t| Sv.", - ".sssssss.| +((BB|fOC|.", - ".........| |----|---|.", - ".........| + + d|.", - ".........v |o |---|.", - "......1..v |d @@|.", - ".........|-[----v---v-|.", - ".........##ss##########.", - "...........ss...........", - "..#......ssssssssssss...", - "...#.....sssHsHssssss...", - ".T.......sssNNNssssss...", - ".........sssHsHssssss...", - "........................", - "........................" - ], - "set": [ - { "point": "terrain", "id": "t_tree_young", "x": [ 13, 22 ], "y": [ 0, 0 ], "chance": 10 }, - { "point": "terrain", "id": "t_dirt", "x": [ 23, 23 ], "y": [ 0, 23 ], "repeat": [ 5, 10 ] }, - { "point": "terrain", "id": "t_dirt", "x": [ 0, 0 ], "y": [ 0, 23 ], "repeat": [ 5, 10 ] }, - { "point": "terrain", "id": "t_dirt", "x": [ 0, 23 ], "y": [ 22, 23 ], "repeat": [ 9, 17 ] }, - { "point": "furniture", "id": "f_dahlia", "x": [ 8, 8 ], "y": [ 1, 8 ], "repeat": [ 1, 2 ] } + "._______p&---...........", + "._______.##*o##oo##oo##.", + "._______^#y RRR HHHHs#.", + "._______.o o.", + "._______.# ### lll #.", + "._______.# hfh Y#.", + "._______.o hfh 4o.", + "._______.# 3#.", + "._______.# ||||||6 2#.", + "._______~* |St8Q|7 5o.", + "._______~#L +(((9|FO1#.", + "~~~~~~~~~#IA |||||||||#.", + ".:.....~%#I + yb|Dzd#.", + "..&&&..~%o$ |@ ||+|#.", + "..&X&.:~%o> |@sT I#.", + "..&&&..~%##[####o###o##.", + ".:.....~.%%~~%%%%%%%%%^.", + ".......~...~~...........", + ".......~.~~~~~~~~jjj~...", + ".......~.~~~G~G~~~K~~...", + ".......~~~~~KKK~~~~~~...", + ".........~~~G~G~~~~~~...", + ".............:.......:..", + ".........:.............." ], + "palettes": [ "standard_domestic_palette" ], "terrain": { - "#": "t_shrub", + "%": [ "t_region_shrub", "t_region_shrub_fruit", "t_region_shrub_decorative" ], + ":": [ [ "t_region_tree_fruit", 2 ], [ "t_region_tree_nut", 2 ], "t_region_tree_shade" ], + "&": "t_region_groundcover_urban", + "$": "t_railing_h", + "_": "t_pavement", + "G": "t_concrete", + "K": "t_concrete", + "~": "t_concrete", + "j": "t_concrete", "(": "t_linoleum_gray", - "+": "t_door_c", - "-": "t_wall", - ".": "t_grass", - "P": "t_grass", - "1": "t_tree_peach", - ";": "t_door_locked", - "?": "t_floor", - "@": "t_floor", - "Y": "t_floor", - "B": "t_linoleum_gray", - "C": "t_floor", - "D": "t_floor", - "H": "t_sidewalk", - "N": "t_sidewalk", - "O": "t_floor", - "S": "t_floor", - "T": "t_tree", - "U": "t_linoleum_gray", - "[": "t_door_glass_c", - "c": "t_floor", - "d": "t_floor", - "f": "t_floor", - "h": "t_floor", - "n": "t_floor", - "o": "t_floor", - "s": "t_sidewalk", + "8": "t_linoleum_gray", "t": "t_linoleum_gray", - "v": "t_window_domestic", - "|": "t_wall" - }, - "furniture": { - "?": "f_sofa", - "@": "f_bed", - "B": "f_bathtub", - "C": "f_cupboard", - "D": "f_trashcan", - "H": "f_chair", - "N": "f_table", - "P": "f_mailbox", - "Y": "f_rack_coat", - "O": "f_oven", - "S": "f_sink", - "U": "f_sink", - "c": "f_counter", - "d": "f_dresser", - "f": "f_fridge", - "h": "f_chair", - "n": "f_table", - "o": "f_bookcase" - }, - "toilets": { "t": { } }, - "items": { - "Y": { "item": "coat_rack", "chance": 30, "repeat": [ 1, 4 ] }, - "P": { "item": "mail", "chance": 30, "repeat": [ 2, 5 ] } + "9": "t_linoleum_gray", + "S": "t_linoleum_gray", + "Q": "t_linoleum_gray", + "[": "t_door_glass_c" }, + "furniture": { "&": "f_region_flower" }, + "set": [ { "point": "furniture", "id": "f_dahlia", "x": [ 8, 8 ], "y": [ 1, 8 ], "repeat": [ 1, 2 ] } ], "place_loot": [ - { "group": "bedroom", "x": [ 15, 17 ], "y": [ 12, 14 ], "chance": 80, "repeat": [ 1, 4 ] }, - { "group": "bed", "x": [ 20, 21 ], "y": [ 14, 14 ], "chance": 90, "repeat": [ 1, 2 ] }, - { "group": "shirts", "x": [ 21, 21 ], "y": [ 12, 12 ], "chance": 90, "repeat": [ 1, 2 ] }, - { "group": "dresser", "x": [ 14, 14 ], "y": [ 14, 14 ], "chance": 85, "repeat": [ 1, 4 ] }, - { "group": "homebooks", "x": [ 14, 15 ], "y": [ 2, 2 ], "chance": 65, "repeat": [ 1, 2 ] }, - { "group": "homebooks", "x": [ 14, 14 ], "y": [ 13, 13 ], "chance": 75, "repeat": [ 1, 2 ] }, - { "group": "fridge", "x": [ 19, 19 ], "y": [ 10, 10 ], "chance": 90, "repeat": [ 1, 5 ] }, - { "group": "oven", "x": [ 20, 20 ], "y": [ 10, 10 ], "chance": 75, "repeat": [ 1, 3 ] }, - { "group": "pasta", "x": [ 21, 21 ], "y": [ 10, 10 ], "chance": 50, "repeat": [ 1, 2 ] }, - { "group": "cannedfood", "x": [ 21, 21 ], "y": [ 10, 10 ], "chance": 75, "repeat": [ 1, 3 ] }, - { "group": "kitchen", "x": [ 21, 21 ], "y": [ 7, 8 ], "chance": 80, "repeat": [ 1, 2 ] }, - { "group": "trash", "x": [ 21, 21 ], "y": [ 5, 5 ], "chance": 75, "repeat": [ 1, 3 ] }, - { "group": "dining", "x": [ 14, 14 ], "y": [ 5, 6 ], "chance": 80, "repeat": [ 1, 3 ] }, - { "group": "livingroom", "x": [ 17, 21 ], "y": [ 2, 3 ], "chance": 90, "repeat": [ 1, 4 ] }, - { "group": "softdrugs", "x": [ 14, 17 ], "y": [ 9, 10 ], "chance": 75, "repeat": [ 1, 3 ] }, - { "group": "cleaning", "x": [ 14, 17 ], "y": [ 9, 10 ], "chance": 90, "repeat": [ 1, 2 ] }, { "group": "barbecue", "x": [ 12, 14 ], "y": [ 20, 20 ], "chance": 75, "repeat": [ 1, 4 ] }, { "item": "television", "x": [ 19, 19 ], "y": [ 4, 4 ], "chance": 75 }, { "item": "char_smoker", "x": [ 18, 18 ], "y": [ 19, 19 ], "chance": 85 }, { "item": "charcoal", "x": [ 18, 18 ], "y": [ 19, 19 ], "chance": 60, "repeat": [ 1, 3 ] } ], + "place_nested": [ + { + "chunks": [ + [ "null", 10 ], + [ "roof_6x6_garden_4", 15 ], + [ "roof_6x6_garden_1", 15 ], + [ "greenhouse_6x6_herbal", 20 ], + [ "greenhouse_6x6_vegetable", 25 ], + [ "pond_6x6", 20 ], + [ "shed_6x6_junk", 25 ], + [ "shed_6x6_woodworker", 20 ] + ], + "x": 1, + "y": 17 + } + ], "place_vehicles": [ { "vehicle": "suburban_home", "x": 5, "y": 4, "chance": 10, "rotation": 90 } ] } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "house_patio_roof", + "object": { + "fill_ter": "t_shingle_flat_roof", + "rows": [ + " ", + " |2222222222223 ", + " 5............3 ", + " |............3 ", + " |............3 ", + " |............3 ", + " |............3 ", + " |............3 ", + " |............3 ", + " |............3 ", + " |............3 ", + " |............3 ", + " |............3 ", + " |............3 ", + " |............3 ", + " |------------5 ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + ], + "palettes": [ "roof_palette" ], + "terrain": { ".": "t_shingle_flat_roof" } + } } ] diff --git a/data/json/mapgen/house/house_porch.json b/data/json/mapgen/house/house_porch.json index ca5e375269780..d47c7666b51da 100644 --- a/data/json/mapgen/house/house_porch.json +++ b/data/json/mapgen/house/house_porch.json @@ -2,135 +2,96 @@ { "type": "mapgen", "method": "json", - "om_terrain": [ "house" ], - "weight": 300, + "om_terrain": [ "house_porch" ], + "weight": 200, "object": { "fill_ter": "t_floor", "rows": [ - ".....#ss#......sssssss..", - "......ss.......sssssss..", - ".....#ss#......sssssss..", - "......ssp......sssssss..", - ".....#ssssssssssssssss..", - "..igigssgigi...sssssss..", - ".IAAAI IAAAI..sssssss..", - ".a a..sssssss..", - ".anbb bb a..sssssss..", - ".|-v--::--v-|..sssssss..", - ".|nnnn P D|..sssssss..", - ".| |..#######..", - ".|??nK 0--vv---vv-|.", - ".| Kc f|.", - ".|6 hNNNh Kc Ov.", - ".|c hNNNh - Sv.", - ".|c D DC|.", - ".--vv-- -------+---+--|.", - "......| |@@ d|t(U|d n|.", - "...1..| + |BB(+ @@|.", - "......+ | |---|o @@|.", - "......|n|oo +d|d+ n|.", - "......-v--vv-------vv--.", + ".....:--p......!!!!!!!..", + "......--.......!!!!!!!..", + ".....:--:......!!!!!!!..", + "......--:......!!!!!!!..", + ".....:---------!!!!!!!..", + ".%%%%%--%%%%%..!!!!!!!..", + ".$___$~~$___$..!!!!!!!..", + "._~~~~~~~~~~_..!!!!!!!..", + "._GKG~~~~jj~_..!!!!!!!..", + ".##o##**##o##..!!!!!!!..", + ".#ssxx y y#..!!!!!!!..", + ".# #^.%%%%%%%..", + ".# a##oo###oo##.", + ".#HHsE AJ347F#.", + ".#r hfh AJ Oo.", + ".#rA hfh 5o.", + ".#r Y 66Y 12#.", + ".##oo## |||||||+|||+||#.", + ".....^# |@@ d|t(S|d s#.", + "...:..+ + AI|8(9|b @@#.", + "......# | I|||||R @@#.", + "......#>|RR +D|D+ s#.", + "......#o##oo#######oo##.", "........................" ], - "set": [ - { "point": "terrain", "id": "t_dirt", "x": [ 23, 23 ], "y": [ 0, 11 ], "repeat": [ 2, 5 ] }, - { "point": "terrain", "id": "t_dirt", "x": [ 23, 23 ], "y": [ 0, 23 ], "repeat": [ 5, 10 ] }, - { "point": "terrain", "id": "t_dirt", "x": [ 0, 0 ], "y": [ 0, 23 ], "repeat": [ 5, 10 ] }, - { "point": "terrain", "id": "t_dirt", "x": [ 0, 23 ], "y": [ 23, 23 ], "repeat": [ 4, 8 ] } - ], + "palettes": [ "standard_domestic_palette" ], "terrain": { - "#": "t_shrub", - "(": "t_linoleum_gray", - "+": "t_door_c", - "-": "t_wall", - ".": "t_grass", - "p": "t_grass", - "0": "t_floor", - "1": "t_tree_pine", - "6": "t_console_broken", - ":": "t_door_locked_interior", - "?": "t_floor", - "@": "t_floor", - "A": "t_railing_h", - "B": "t_linoleum_gray", - "C": "t_floor", - "D": "t_floor", - "I": "t_column", - "K": "t_floor", - "N": "t_carpet_red", - "O": "t_floor", - "P": "t_floor", - "S": "t_floor", - "U": "t_linoleum_gray", - "a": "t_railing_v", - "b": "t_floor", - "c": "t_floor", - "d": "t_floor", - "f": "t_floor", - "g": "t_grass", - "h": "t_carpet_red", - "i": "t_grass", - "n": "t_floor", - "o": "t_floor", - "s": "t_sidewalk", + "~": "t_thconc_floor", + "j": "t_thconc_floor", + "G": "t_thconc_floor", + "K": "t_thconc_floor", + "!": "t_concrete", + ":": [ [ "t_region_tree_fruit", 2 ], [ "t_region_tree_nut", 2 ], "t_region_tree_shade" ], + "_": "t_railing", + "%": "t_region_groundcover_urban", + "9": "t_linoleum_gray", "t": "t_linoleum_gray", - "v": "t_window_domestic", - "|": "t_wall" - }, - "furniture": { - "0": "f_fireplace", - "?": "f_sofa", - "@": "f_bed", - "B": "f_bathtub", - "C": "f_cupboard", - "D": "f_trashcan", - "K": "f_armchair", - "N": "f_table", - "O": "f_oven", - "P": "f_indoor_plant", - "S": "f_sink", - "U": "f_sink", - "b": "f_bench", - "p": "f_mailbox", - "c": "f_counter", - "d": "f_dresser", - "f": "f_fridge", - "g": "f_bluebell", - "h": "f_chair", - "i": "f_dahlia", - "n": "f_table", - "o": "f_bookcase" + "S": "t_linoleum_gray", + "8": "t_linoleum_gray", + "(": "t_linoleum_gray", + "$": "t_column", + "f": "t_carpet_red", + "h": "t_carpet_red" }, - "toilets": { "t": { } }, - "items": { "p": { "item": "mail", "chance": 30, "repeat": [ 2, 5 ] } }, + "furniture": { "%": "f_region_flower" }, "place_loot": [ - { "group": "bedroom", "x": [ 18, 21 ], "y": [ 18, 21 ], "chance": 80, "repeat": [ 1, 4 ] }, - { "group": "bed", "x": [ 20, 21 ], "y": [ 19, 20 ], "chance": 90, "repeat": [ 1, 3 ] }, - { "group": "dresser", "x": [ 18, 18 ], "y": [ 18, 18 ], "chance": 85, "repeat": [ 1, 3 ] }, - { "group": "shirts", "x": [ 16, 16 ], "y": [ 21, 21 ], "chance": 90, "repeat": [ 1, 2 ] }, - { "group": "bedroom", "x": [ 9, 12 ], "y": [ 18, 21 ], "chance": 80, "repeat": [ 1, 4 ] }, - { "group": "bed", "x": [ 9, 10 ], "y": [ 18, 18 ], "chance": 90, "repeat": [ 1, 2 ] }, - { "group": "dresser", "x": [ 12, 12 ], "y": [ 18, 18 ], "chance": 85, "repeat": [ 1, 3 ] }, - { "group": "shirts", "x": [ 14, 14 ], "y": [ 21, 21 ], "chance": 90, "repeat": [ 1, 2 ] }, - { "group": "homebooks", "x": [ 18, 18 ], "y": [ 20, 20 ], "chance": 70, "repeat": [ 1, 2 ] }, - { "group": "homebooks", "x": [ 9, 10 ], "y": [ 21, 21 ], "chance": 70, "repeat": [ 1, 2 ] }, - { "group": "magazines", "x": [ 7, 7 ], "y": [ 21, 21 ], "chance": 80, "repeat": [ 1, 3 ] }, - { "group": "fridge", "x": [ 21, 21 ], "y": [ 13, 13 ], "chance": 90, "repeat": [ 1, 5 ] }, - { "group": "oven", "x": [ 21, 21 ], "y": [ 14, 14 ], "chance": 75, "repeat": [ 1, 3 ] }, - { "group": "pasta", "x": [ 21, 21 ], "y": [ 16, 16 ], "chance": 50, "repeat": [ 1, 2 ] }, - { "group": "cannedfood", "x": [ 21, 21 ], "y": [ 16, 16 ], "chance": 70, "repeat": [ 1, 3 ] }, - { "group": "kitchen", "x": [ 17, 21 ], "y": [ 13, 16 ], "chance": 80, "repeat": [ 1, 3 ] }, - { "group": "trash", "x": [ 20, 20 ], "y": [ 16, 16 ], "chance": 70, "repeat": [ 1, 3 ] }, - { "group": "dining", "x": [ 9, 11 ], "y": [ 14, 15 ], "chance": 75, "repeat": [ 1, 2 ] }, - { "group": "livingroom", "x": [ 2, 10 ], "y": [ 10, 12 ], "chance": 90, "repeat": [ 1, 4 ] }, - { "group": "trash", "x": [ 11, 11 ], "y": [ 10, 10 ], "chance": 60, "repeat": [ 1, 2 ] }, - { "group": "softdrugs", "x": [ 14, 16 ], "y": [ 18, 19 ], "chance": 75, "repeat": [ 1, 3 ] }, - { "group": "cleaning", "x": [ 14, 16 ], "y": [ 18, 19 ], "chance": 90, "repeat": [ 1, 2 ] }, - { "group": "office", "x": [ 2, 4 ], "y": [ 13, 16 ], "chance": 50, "repeat": [ 1, 3 ] }, - { "group": "trash", "x": [ 5, 5 ], "y": [ 16, 16 ], "chance": 70, "repeat": [ 1, 2 ] }, { "group": "alcohol", "x": [ 2, 2 ], "y": [ 8, 8 ], "chance": 15 }, { "item": "television", "x": [ 4, 4 ], "y": [ 10, 10 ], "chance": 75 } ] } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "house_porch_roof", + "object": { + "fill_ter": "t_shingle_flat_roof", + "rows": [ + " ", + " ", + " ", + " ", + " ", + " ", + " ............ ", + " ............ ", + " ............ ", + " |22222222223 ", + " |..........3 ", + " |..........3 ", + " |.........~52222222223 ", + " |....................3 ", + " |....................3 ", + " |....................3 ", + " |.............=......3 ", + " |----5...............3 ", + " |...............3 ", + " |.....&.........3 ", + " |...............3 ", + " |...............3 ", + " |---------------3 ", + " " + ], + "palettes": [ "roof_palette" ], + "terrain": { ".": "t_shingle_flat_roof" } + } } ] diff --git a/data/json/mapgen/house/house_rv.json b/data/json/mapgen/house/house_rv.json index 8bfbc34ccf9bb..9c1e4fe18d53a 100644 --- a/data/json/mapgen/house/house_rv.json +++ b/data/json/mapgen/house/house_rv.json @@ -2,112 +2,86 @@ { "type": "mapgen", "method": "json", - "om_terrain": [ "house" ], + "om_terrain": [ "house_rv" ], "weight": 300, "object": { "fill_ter": "t_floor", "rows": [ - ".#ssssssss..###...s.....", - ".#ssssssssp----vv-;----.", - ".#ssssssss.|ooo ?|.", - ".#ssssssss.| n ?|.", - ".#ssssssss.| ?|.", - ".#ssssssss.|???? |.", - ".#ssssssss.| |.", - ".#ssssssss.| hhh v.", - "..sssssssss; nnn v.", - "..ssssssss.|Y nnn v.", - "..ssssssss.| hhh v.", - "..ssssssss.| |.", - ".|---------|+-----+---|.", - ".vSCfO | | t B|.", - ".v + | BBv.", - ".v ccc rrr| + S BB|.", - ".|---------| |--------|.", - ".|d | | rrrr |.", - ".|@@ | | |.", - ".|@@ + + rrrr |.", - ".| | | |.", - ".| | | cccc |.", - ".----vv-----v----------.", - "........................" - ], - "set": [ - { "point": "terrain", "id": "t_dirt", "x": [ 23, 23 ], "y": [ 0, 23 ], "repeat": [ 5, 10 ] }, - { "point": "terrain", "id": "t_dirt", "x": [ 0, 23 ], "y": [ 23, 23 ], "repeat": [ 5, 8 ] } + ".%~~~~~~~~p.%%%..---....", + ".%~~~~~~~~.####oo#*####.", + ".%~~~~~~~~.#RRR L E#.", + ".%~~~~~~~~.# s#.", + ".%~~~~~~~~.# ll E#.", + ".%~~~~~~~~.#HHHH T#.", + ".%~~~~~~~~.# #.", + ".%~~~~~~~~.#L hhh o.", + "..~~~~~~~~~* fff o.", + "..~~~~~~~~.# hhh o.", + "..~~~~~~~~.# o.", + "..~~~~~~~~^# AAA y#.", + ".########### ||| JJJ||#.", + ".#BBy + |66 7Fo.", + ".o || || |Y 5o.", + ".#S88Yt|Q U| 43O21o.", + ".#|||||||||| ||+||||||#.", + ".#d b +D| |zz666666#.", + ".#@@ y||| |z z#.", + ".#@@ + + UUUUUU#.", + ".#s h|+| A #.", + ".# TEy II|>|gzqqqNNN#.", + ".####oo#####o##########.", + ".....................^.." ], + "palettes": [ "standard_domestic_palette" ], "terrain": { - "#": "t_shrub", - "+": "t_door_c", - "-": "t_wall", - ".": "t_grass", - "p": "t_grass", - ";": "t_door_locked", - "?": "t_floor", - "@": "t_floor", - "B": "t_floor", - "C": "t_floor", - "D": "t_floor", - "O": "t_floor", - "Y": "t_floor", - "S": "t_floor", - "c": "t_floor", - "d": "t_floor", - "f": "t_floor", - "h": "t_floor", - "n": "t_floor", - "o": "t_floor", - "r": "t_floor", - "s": "t_sidewalk", - "v": "t_window_domestic", - "|": "t_wall" - }, - "furniture": { - "?": "f_sofa", - "@": "f_bed", - "B": "f_bathtub", - "C": "f_cupboard", - "p": "f_mailbox", - "Y": "f_rack_coat", - "D": "f_trashcan", - "O": "f_oven", - "S": "f_sink", - "c": "f_counter", - "d": "f_dresser", - "f": "f_fridge", - "h": "f_chair", - "n": "f_table", - "o": "f_bookcase", - "r": "f_rack" - }, - "toilets": { "t": { } }, - "items": { - "Y": { "item": "coat_rack", "chance": 30, "repeat": [ 1, 4 ] }, - "p": { "item": "mail", "chance": 30, "repeat": [ 2, 5 ] } + "%": [ "t_region_shrub", "t_region_shrub_fruit", "t_region_shrub_decorative" ], + "G": "t_concrete", + "K": "t_concrete", + "~": "t_concrete", + "j": "t_concrete" }, "place_loot": [ - { "group": "bed", "x": [ 2, 3 ], "y": [ 18, 19 ], "chance": 90, "repeat": [ 1, 3 ] }, - { "group": "livingroom", "x": [ 12, 21 ], "y": [ 2, 6 ], "chance": 90, "repeat": [ 1, 4 ] }, - { "group": "dining", "x": [ 16, 18 ], "y": [ 8, 9 ], "chance": 80, "repeat": [ 1, 4 ] }, - { "group": "bedroom", "x": [ 1, 10 ], "y": [ 17, 21 ], "chance": 80, "repeat": [ 1, 5 ] }, - { "group": "dresser", "x": [ 2, 2 ], "y": [ 17, 17 ], "chance": 85, "repeat": [ 1, 4 ] }, - { "group": "consumer_electronics", "x": [ 1, 10 ], "y": [ 17, 21 ], "chance": 20, "repeat": [ 1, 2 ] }, - { "group": "guns_pistol_common", "x": [ 2, 2 ], "y": [ 17, 17 ], "chance": 5, "ammo": 90, "magazine": 100 }, - { "group": "novels", "x": [ 12, 14 ], "y": [ 2, 2 ], "chance": 85, "repeat": [ 1, 3 ] }, - { "group": "cleaning", "x": [ 14, 21 ], "y": [ 13, 15 ], "chance": 90, "repeat": [ 1, 2 ] }, - { "group": "softdrugs", "x": [ 14, 21 ], "y": [ 13, 15 ], "chance": 75, "repeat": [ 1, 3 ] }, - { "group": "kitchen", "x": [ 2, 10 ], "y": [ 13, 15 ], "chance": 75, "repeat": [ 1, 3 ] }, - { "group": "fridge", "x": [ 4, 4 ], "y": [ 13, 13 ], "chance": 90, "repeat": [ 1, 5 ] }, - { "group": "oven", "x": [ 5, 5 ], "y": [ 13, 13 ], "chance": 75, "repeat": [ 1, 3 ] }, - { "group": "cannedfood", "x": [ 9, 10 ], "y": [ 15, 15 ], "chance": 40, "repeat": [ 1, 2 ] }, - { "group": "pasta", "x": [ 3, 5 ], "y": [ 15, 15 ], "chance": 40, "repeat": [ 1, 2 ] }, - { "group": "knifeblock", "x": [ 3, 5 ], "y": [ 15, 15 ], "chance": 70, "repeat": [ 1, 2 ] }, - { "group": "cannedfood", "x": [ 16, 19 ], "y": [ 17, 17 ], "chance": 60, "repeat": [ 1, 3 ] }, - { "group": "camping", "x": [ 16, 19 ], "y": [ 19, 19 ], "chance": 70, "repeat": [ 1, 4 ] }, - { "group": "softdrugs", "x": [ 16, 19 ], "y": [ 21, 21 ], "chance": 60, "repeat": [ 1, 3 ] } + { "group": "guns_pistol_common", "x": 2, "y": 17, "chance": 5, "ammo": 90, "magazine": 100 }, + { "group": "camping", "x": [ 16, 19 ], "y": 19, "chance": 70, "repeat": [ 1, 4 ] } ], "place_monsters": [ { "monster": "GROUP_ZOMBIE", "x": [ 2, 21 ], "y": [ 2, 21 ], "chance": 2 } ], - "place_vehicles": [ { "vehicle": "rv", "x": 5, "y": 4, "chance": 10, "rotation": 270 } ] + "place_vehicles": [ { "vehicle": "rv", "x": 5, "y": 4, "chance": 5, "rotation": 270 } ] + } + }, + { + "type": "mapgen", + "method": "json", + "om_terrain": "house_rv_roof", + "object": { + "fill_ter": "t_shingle_flat_roof", + "rows": [ + " ", + " |22222222223 ", + " |..........3 ", + " |..........3 ", + " |..........3 ", + " |..........3 ", + " |....&.....3 ", + " |..........3 ", + " |..........3 ", + " |..........3 ", + " |..........3 ", + " |..........3 ", + " |2222222225..........3 ", + " |....................3 ", + " |....................3 ", + " |...:................3 ", + " |....................3 ", + " |....................3 ", + " |....................3 ", + " |..............=.....3 ", + " |....................3 ", + " |....................3 ", + " |------------------5-3 ", + " " + ], + "palettes": [ "roof_palette" ], + "terrain": { ".": "t_shingle_flat_roof" } } } ] diff --git a/data/json/mapgen_palettes/house_general_palette.json b/data/json/mapgen_palettes/house_general_palette.json index 240430bb81f81..d5a63d9b5ef0b 100644 --- a/data/json/mapgen_palettes/house_general_palette.json +++ b/data/json/mapgen_palettes/house_general_palette.json @@ -88,8 +88,8 @@ "t_window_no_curtains_open", [ "t_curtains", 5 ] ], - "<": "t_stairs_up", - ">": "t_stairs_down" + "<": "t_wood_stairs_up", + ">": "t_wood_stairs_down" }, "liquids": { "g": { "liquid": "water_clean", "amount": [ 0, 100 ] } }, "items": { diff --git a/data/json/npcs/TALK_FACTION_CAMP.json b/data/json/npcs/TALK_FACTION_CAMP.json index ca3fca864c806..9513984d1bc5c 100644 --- a/data/json/npcs/TALK_FACTION_CAMP.json +++ b/data/json/npcs/TALK_FACTION_CAMP.json @@ -20,6 +20,12 @@ "switch": true, "default": true }, + { + "text": "We need to abandon this camp.", + "condition": { "npc_at_om_location": "FACTION_CAMP_ANY" }, + "topic": "TALK_DONE", + "effect": "abandon_camp" + }, { "text": "Show me what needs to be done at the camp.", "topic": "TALK_DONE", diff --git a/data/json/overmap/multitile_city_buildings.json b/data/json/overmap/multitile_city_buildings.json index 1ae188424d61b..aa33aebc5ea00 100644 --- a/data/json/overmap/multitile_city_buildings.json +++ b/data/json/overmap/multitile_city_buildings.json @@ -2746,5 +2746,55 @@ "id": "s_hunting", "locations": [ "land" ], "overmaps": [ { "point": [ 0, 0, 0 ], "overmap": "s_hunting_north" }, { "point": [ 0, 0, 1 ], "overmap": "s_hunting_roof_north" } ] + }, + { + "type": "city_building", + "id": "house_rv", + "locations": [ "land" ], + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "house_rv_north" }, + { "point": [ 0, 0, 1 ], "overmap": "house_rv_roof_north" }, + { "point": [ 0, 0, -1 ], "overmap": "basement" } + ] + }, + { + "type": "city_building", + "id": "house_porch", + "locations": [ "land" ], + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "house_porch_north" }, + { "point": [ 0, 0, 1 ], "overmap": "house_porch_roof_north" }, + { "point": [ 0, 0, -1 ], "overmap": "basement" } + ] + }, + { + "type": "city_building", + "id": "house_patio", + "locations": [ "land" ], + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "house_patio_north" }, + { "point": [ 0, 0, 1 ], "overmap": "house_patio_roof_north" }, + { "point": [ 0, 0, -1 ], "overmap": "basement" } + ] + }, + { + "type": "city_building", + "id": "house_modern_1", + "locations": [ "land" ], + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "house_modern_1_north" }, + { "point": [ 0, 0, 1 ], "overmap": "house_modern_1_roof_north" }, + { "point": [ 0, 0, -1 ], "overmap": "basement" } + ] + }, + { + "type": "city_building", + "id": "house_library", + "locations": [ "land" ], + "overmaps": [ + { "point": [ 0, 0, 0 ], "overmap": "house_library_north" }, + { "point": [ 0, 0, 1 ], "overmap": "house_04_roof_north" }, + { "point": [ 0, 0, -1 ], "overmap": "basement" } + ] } ] diff --git a/data/json/overmap/overmap_terrain/overmap_terrain_residential.json b/data/json/overmap/overmap_terrain/overmap_terrain_residential.json index fde129afae937..9f482a2bdb9d3 100644 --- a/data/json/overmap/overmap_terrain/overmap_terrain_residential.json +++ b/data/json/overmap/overmap_terrain/overmap_terrain_residential.json @@ -801,5 +801,82 @@ "color": "light_green", "see_cost": 2, "flags": [ "SIDEWALK", "GENERIC_LOOT" ] + }, + { + "type": "overmap_terrain", + "id": "house_rv", + "name": "house", + "copy-from": "generic_city_building", + "color": "light_green", + "see_cost": 2, + "flags": [ "SIDEWALK", "GENERIC_LOOT" ] + }, + { + "type": "overmap_terrain", + "id": "house_rv_roof", + "name": "house", + "copy-from": "generic_city_building", + "color": "light_green", + "see_cost": 2 + }, + { + "type": "overmap_terrain", + "id": "house_porch", + "name": "house", + "copy-from": "generic_city_building", + "color": "light_green", + "see_cost": 2, + "flags": [ "SIDEWALK", "GENERIC_LOOT" ] + }, + { + "type": "overmap_terrain", + "id": "house_porch_roof", + "name": "house", + "copy-from": "generic_city_building", + "color": "light_green", + "see_cost": 2 + }, + { + "type": "overmap_terrain", + "id": "house_patio", + "name": "house", + "copy-from": "generic_city_building", + "color": "light_green", + "see_cost": 2, + "flags": [ "SIDEWALK", "GENERIC_LOOT" ] + }, + { + "type": "overmap_terrain", + "id": "house_patio_roof", + "name": "house", + "copy-from": "generic_city_building", + "color": "light_green", + "see_cost": 2 + }, + { + "type": "overmap_terrain", + "id": "house_library", + "name": "house", + "copy-from": "generic_city_building", + "color": "light_green", + "see_cost": 2, + "flags": [ "SIDEWALK", "GENERIC_LOOT" ] + }, + { + "type": "overmap_terrain", + "id": "house_modern_1", + "name": "house", + "copy-from": "generic_city_building", + "color": "light_green", + "see_cost": 2, + "flags": [ "SIDEWALK", "GENERIC_LOOT" ] + }, + { + "type": "overmap_terrain", + "id": "house_modern_1_roof", + "name": "house", + "copy-from": "generic_city_building", + "color": "light_green", + "see_cost": 2 } ] diff --git a/data/json/recipes/recipe_food.json b/data/json/recipes/recipe_food.json index 09279e59ea1a3..79b92ed0149ab 100644 --- a/data/json/recipes/recipe_food.json +++ b/data/json/recipes/recipe_food.json @@ -304,6 +304,7 @@ [ "seed_pumpkin", 4 ], [ "seed_sunflower", 2 ], [ "seed_canola", 4 ], + [ "seed_grapes", 6 ], [ "seed_weed", 6 ] ] ] diff --git a/data/json/recipes/recipe_others.json b/data/json/recipes/recipe_others.json index 91e0761bc3377..0ab7fd5efe5c0 100644 --- a/data/json/recipes/recipe_others.json +++ b/data/json/recipes/recipe_others.json @@ -4399,7 +4399,7 @@ "time": "2 m", "autolearn": true, "qualities": [ { "id": "DIG", "level": 3 } ], - "components": [ [ [ "bag_canvas", 1 ] ], [ [ "material_sand", 60 ] ] ] + "components": [ [ [ "bag_canvas", 1 ] ], [ [ "material_sand", 3200 ] ] ] }, { "type": "recipe", diff --git a/data/json/regional_map_settings.json b/data/json/regional_map_settings.json index bdd3c57a1daf3..fdc35e55c8eca 100644 --- a/data/json/regional_map_settings.json +++ b/data/json/regional_map_settings.json @@ -537,7 +537,7 @@ "houses": { "house_w_1": 50, "house_two_story_basement": 1, - "house": 1000, + "house": 700, "house_prepper": 20, "house_base": 333, "duplex": 40, @@ -566,7 +566,12 @@ "house_toolshed": 50, "house_suicide": 20, "house_quiverfull": 30, - "house_inner_garden": 40, + "house_rv": 50, + "house_porch": 50, + "house_patio": 50, + "house_modern_1": 50, + "house_library": 50, + "house_inner_garden": 50, "emptyresidentiallot": 20, "apartments_con_new": 10, "apartments_mod_new": 10, diff --git a/data/mods/Magiclysm/Spells/technomancer.json b/data/mods/Magiclysm/Spells/technomancer.json index a8e4091c56657..97b76dcd82b02 100644 --- a/data/mods/Magiclysm/Spells/technomancer.json +++ b/data/mods/Magiclysm/Spells/technomancer.json @@ -321,6 +321,29 @@ "max_duration": 6000, "duration_increment": 200 }, + { + "id": "holographic_transposition", + "type": "SPELL", + "name": "Holographic Transposition", + "description": "Allows you to swap places with a previously existing holographic image of yourself. If the universe itself can't tell you apart, who could?", + "valid_targets": [ "hostile", "ally" ], + "targeted_monster_ids": [ "mon_mirror_image", "mon_hologram" ], + "flags": [ "NO_LEGS", "LOUD", "SOMATIC", "SWAP_POS" ], + "effect": "target_attack", + "spell_class": "TECHNOMANCER", + "energy_source": "MANA", + "difficulty": 3, + "max_level": 20, + "base_casting_time": 100, + "casting_time_increment": -1, + "final_casting_time": 80, + "base_energy_cost": 150, + "energy_increment": -2, + "final_energy_cost": 100, + "min_range": 20, + "max_range": 30, + "range_increment": 1 + }, { "type": "SPELL", "name": "X-ray Vision", diff --git a/data/mods/Magiclysm/itemgroups/spellbooks.json b/data/mods/Magiclysm/itemgroups/spellbooks.json index a31b1c587008c..fb5a696259608 100644 --- a/data/mods/Magiclysm/itemgroups/spellbooks.json +++ b/data/mods/Magiclysm/itemgroups/spellbooks.json @@ -91,6 +91,7 @@ [ "spell_scroll_storm_hammer", 35 ], [ "spell_scroll_animated_blade", 35 ], [ "spell_scroll_mirror_image", 15 ], + [ "spell_scroll_holographic_transposition", 15 ], [ "spell_scroll_dark_sight", 30 ] ] }, diff --git a/data/mods/Magiclysm/items/spell_scrolls.json b/data/mods/Magiclysm/items/spell_scrolls.json index 38435e02f4f75..db87110388fcd 100644 --- a/data/mods/Magiclysm/items/spell_scrolls.json +++ b/data/mods/Magiclysm/items/spell_scrolls.json @@ -34,6 +34,14 @@ "description": "A magical aura distorts light around your body, making it easier to dodge enemy attacks.", "use_action": { "type": "learn_spell", "spells": [ "obfuscated_body" ] } }, + { + "type": "GENERIC", + "copy-from": "spell_scroll", + "id": "spell_scroll_holographic_transposition", + "name": { "str": "Scroll of Holographic Transposition", "str_pl": "Scrolls of Holographic Transposition" }, + "description": "Allows you to swap places with a previously existing holographic image of yourself. If the universe itself can't tell you apart, who could?", + "use_action": { "type": "learn_spell", "spells": [ "holographic_transposition" ] } + }, { "type": "GENERIC", "copy-from": "spell_scroll", diff --git a/data/mods/Magiclysm/items/spellbooks.json b/data/mods/Magiclysm/items/spellbooks.json index dfd7d15439f14..7220c7c489f0d 100644 --- a/data/mods/Magiclysm/items/spellbooks.json +++ b/data/mods/Magiclysm/items/spellbooks.json @@ -151,7 +151,15 @@ "color": "light_gray", "use_action": { "type": "learn_spell", - "spells": [ "dark_sight", "blinding_flash", "obfuscated_body", "create_atomic_light", "mirror_image", "invisibility" ] + "spells": [ + "dark_sight", + "blinding_flash", + "obfuscated_body", + "create_atomic_light", + "mirror_image", + "invisibility", + "holographic_transposition" + ] } }, { diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 7aaa43f3ad598..cf639b95e5599 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -1209,6 +1209,7 @@ See also VEHICLE_JSON.md "name": { "str": "pair of leather socks", "str_pl": "pairs of leather socks" } // Name field, same rules as above. } ], "container" : "null", // What container (if any) this item should spawn within +"repairs_like": "scarf", // If this item does not have recipe, what item to look for a recipe for when repairing it. "color" : "blue", // Color of the item symbol. "symbol" : "[", // The item symbol as it appears on the map. Must be a Unicode string exactly 1 console cell width. "looks_like": "rag", // hint to tilesets if this item has no tile, use the looks_like tile diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9f738828d1ba8..e985457186654 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -123,6 +123,9 @@ IF(TILES) target_link_libraries(libcataclysm-tiles version.lib) IF (BACKTRACE) target_link_libraries(libcataclysm-tiles dbghelp.lib) + IF(LIBBACKTRACE) + target_link_libraries(libcataclysm-tiles backtrace) + ENDIF(LIBBACKTRACE) ENDIF(BACKTRACE) ENDIF(WIN32) @@ -185,6 +188,9 @@ IF(CURSES) target_link_libraries(libcataclysm version.lib) IF (BACKTRACE) target_link_libraries(libcataclysm dbghelp.lib) + IF(LIBBACKTRACE) + target_link_libraries(libcataclysm backtrace) + ENDIF(LIBBACKTRACE) ENDIF(BACKTRACE) ENDIF(WIN32) diff --git a/src/avatar.cpp b/src/avatar.cpp index f81ab0fe29b2b..dd71f8450ea96 100644 --- a/src/avatar.cpp +++ b/src/avatar.cpp @@ -324,7 +324,7 @@ const player *avatar::get_book_reader( const item &book, std::vectordisp_name( true ) ) ); } else if( elem->is_blind() ) { - reasons.push_back( string_format( _( "% is blind." ), elem->disp_name( true ) ) ); + reasons.push_back( string_format( _( "%s is blind." ), elem->disp_name() ) ); } else { int proj_time = time_to_read( book, *elem ); if( proj_time < time_taken ) { diff --git a/src/basecamp.cpp b/src/basecamp.cpp index 1921c4126683b..1cddbd75f418b 100644 --- a/src/basecamp.cpp +++ b/src/basecamp.cpp @@ -9,6 +9,7 @@ #include "avatar.h" #include "clzones.h" +#include "coordinate_conversions.h" #include "output.h" #include "string_formatter.h" #include "translations.h" @@ -579,41 +580,6 @@ std::list basecamp::use_charges( const itype_id &fake_id, int &quantity ) return ret; } -void basecamp::consume_components( map &target_map, const recipe &making, int batch_size ) -{ - const tripoint &origin = target_map.getlocal( get_dumping_spot() ); - const auto &req = making.requirements(); - for( const auto &it : req.get_components() ) { - g->u.consume_items( target_map, g->u.select_item_component( it, batch_size, _inv, - true, is_crafting_component, !by_radio ), batch_size, - is_crafting_component, origin, range ); - } - // this may consume pseudo-resources from fake items - for( const auto &it : req.get_tools() ) { - g->u.consume_tools( target_map, g->u.select_tool_component( it, batch_size, _inv, - DEFAULT_HOTKEYS, true, !by_radio ), batch_size, origin, range, this ); - } - // go back and consume the actual resources - for( basecamp_resource &bcp_r : resources ) { - if( bcp_r.consumed > 0 ) { - target_map.use_charges( origin, range, bcp_r.ammo_id, bcp_r.consumed ); - bcp_r.consumed = 0; - } - } -} - -void basecamp::consume_components( const recipe &making, int batch_size ) -{ - if( by_radio ) { - tinymap target_map; - target_map.load( tripoint( omt_pos.x * 2, omt_pos.y * 2, omt_pos.z ), false ); - consume_components( target_map, making, batch_size ); - target_map.save(); - } else { - consume_components( g->m, making, batch_size ); - } -} - void basecamp::form_crafting_inventory( map &target_map ) { _inv.clear(); @@ -643,7 +609,7 @@ void basecamp::form_crafting_inventory( map &target_map ) } // find available fuel - for( const tripoint &pt : target_map.points_in_radius( origin, range ) ) { + for( const tripoint &pt : target_map.points_in_radius( origin, inv_range ) ) { if( target_map.accessible_items( pt ) ) { for( const item &i : target_map.i_at( pt ) ) { for( basecamp_fuel &bcp_f : fuels ) { @@ -712,3 +678,76 @@ void basecamp::load_data( const std::string &data ) // add space to name replace( name.begin(), name.end(), '_', ' ' ); } + +basecamp_action_components::basecamp_action_components( + const recipe &making, int batch_size, basecamp &base ) : + making_( making ), + batch_size_( batch_size ), + base_( base ) +{ +} + +bool basecamp_action_components::choose_components() +{ + const auto filter = is_crafting_component; + const requirement_data &req = making_.requirements(); + if( !item_selections_.empty() || !tool_selections_.empty() ) { + debugmsg( "Reused basecamp_action_components" ); + return false; + } + for( const auto &it : req.get_components() ) { + comp_selection is = + g->u.select_item_component( it, batch_size_, base_._inv, true, filter, + !base_.by_radio ); + if( is.use_from == cancel ) { + return false; + } + item_selections_.push_back( is ); + } + // this may consume pseudo-resources from fake items + for( const auto &it : req.get_tools() ) { + comp_selection ts = + g->u.select_tool_component( it, batch_size_, base_._inv, DEFAULT_HOTKEYS, true, + !base_.by_radio ); + if( ts.use_from == cancel ) { + return false; + } + tool_selections_.push_back( ts ); + } + return true; +} + +void basecamp_action_components::consume_components() +{ + map *target_map = &g->m; + if( base_.by_radio ) { + map_ = std::make_unique(); + map_->load( omt_to_sm_copy( base_.camp_omt_pos() ), false ); + target_map = map_.get(); + } + const tripoint &origin = target_map->getlocal( base_.get_dumping_spot() ); + const auto &req = making_.requirements(); + if( item_selections_.size() != req.get_components().size() || + tool_selections_.size() != req.get_tools().size() ) { + debugmsg( "Not all selections have been made for basecamp_action_components" ); + } + for( const comp_selection &sel : item_selections_ ) { + g->u.consume_items( *target_map, sel, batch_size_, is_crafting_component, origin, + base_.inv_range ); + } + // this may consume pseudo-resources from fake items + for( const comp_selection &sel : tool_selections_ ) { + g->u.consume_tools( *target_map, sel, batch_size_, origin, base_.inv_range, &base_ ); + } + // go back and consume the actual resources + for( basecamp_resource &bcp_r : base_.resources ) { + if( bcp_r.consumed > 0 ) { + target_map->use_charges( origin, base_.inv_range, bcp_r.ammo_id, bcp_r.consumed ); + bcp_r.consumed = 0; + } + } + if( map_ ) { + map_->save(); + map_.reset(); + } +} diff --git a/src/basecamp.h b/src/basecamp.h index d8dd4aefbc431..0a182560b6534 100644 --- a/src/basecamp.h +++ b/src/basecamp.h @@ -24,8 +24,10 @@ class time_duration; enum class farm_ops; class item; class map; -class recipe; class mission_data; +class recipe; +class requirements_data; +class tinymap; struct expansion_data { std::string type; @@ -144,6 +146,7 @@ class basecamp //change name of camp void set_name( const std::string &new_name ); void query_new_name(); + void abandon_camp(); void add_expansion( const std::string &terrain, const tripoint &new_pos ); void add_expansion( const std::string &bldg, const tripoint &new_pos, const point &dir ); @@ -192,8 +195,6 @@ class basecamp void form_crafting_inventory(); void form_crafting_inventory( map &target_map ); std::list use_charges( const itype_id &fake_id, int &quantity ); - void consume_components( const recipe &making, int batch_size = false ); - void consume_components( map &target_map, const recipe &making, int batch_size ); std::string get_gatherlist() const; /** * spawn items or corpses based on search attempts @@ -322,7 +323,11 @@ class basecamp void serialize( JsonOut &json ) const; void deserialize( JsonIn &jsin ); void load_data( const std::string &data ); + + static constexpr int inv_range = 20; private: + friend class basecamp_action_components; + // lazy re-evaluation of available camp resources void reset_camp_resources(); void add_resource( const itype_id &camp_resource ); @@ -339,9 +344,25 @@ class basecamp std::set fuel_types; std::vector fuels; std::vector resources; - static const int range = 20; inventory _inv; bool by_radio; }; +class basecamp_action_components +{ + public: + basecamp_action_components( const recipe &making, int batch_size, basecamp & ); + + // Returns true iff all necessary components were successfully chosen + bool choose_components(); + void consume_components(); + private: + const recipe &making_; + int batch_size_; + basecamp &base_; + std::vector> item_selections_; + std::vector> tool_selections_; + std::unique_ptr map_; // Used for by-radio crafting +}; + #endif diff --git a/src/crash.cpp b/src/crash.cpp index 763ba2d2dc95c..4a8f21d0c032d 100644 --- a/src/crash.cpp +++ b/src/crash.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -21,85 +22,22 @@ # endif #endif -#include "get_version.h" -#include "path_info.h" - -[[noreturn]] static void crash_terminate_handler(); - #if defined(_WIN32) #if 1 // Hack to prevent reordering of #include "platform_win.h" by IWYU #include "platform_win.h" #endif - #include +#endif + +#include "debug.h" +#include "get_version.h" +#include "path_info.h" // signal handlers are expected to have C linkage, and only use the // common subset of C & C++ extern "C" { -#define BUF_SIZE 4096 - static char buf[BUF_SIZE]; - -#define MODULE_PATH_LEN 512 - static char mod_path[MODULE_PATH_LEN]; - - // on some systems the number of frames to capture have to be less than 63 according to the documentation -#define BT_CNT 62 -#define MAX_NAME_LEN 512 - // ( MAX_NAME_LEN - 1 ) because SYMBOL_INFO already contains a TCHAR -#define SYM_SIZE ( sizeof( SYMBOL_INFO ) + ( MAX_NAME_LEN - 1 ) * sizeof( TCHAR ) ) - static PVOID bt[BT_CNT]; - static struct { - alignas( SYMBOL_INFO ) char storage[SYM_SIZE]; - } sym_storage; - static SYMBOL_INFO *const sym = reinterpret_cast( &sym_storage ); - - // compose message ourselves to avoid potential dynamical allocation. - static void append_str( FILE *const file, char **const beg, const char *const end, - const char *from ) - { - fputs( from, stderr ); - if( file ) { - fputs( from, file ); - } - for( ; *from && *beg + 1 < end; ++from, ++*beg ) { - **beg = *from; - } - } - - static void append_ch( FILE *const file, char **const beg, const char *const end, const char ch ) - { - fputc( ch, stderr ); - if( file ) { - fputc( ch, file ); - } - if( *beg + 1 < end ) { - **beg = ch; - ++*beg; - } - } - - static void append_uint( FILE *const file, char **const beg, const char *const end, - const uintmax_t value ) - { - if( value != 0 ) { - int cnt = 0; - for( uintmax_t tmp = value; tmp; tmp >>= 4, ++cnt ) { - } - for( ; cnt; --cnt ) { - char ch = "0123456789ABCDEF"[( value >> ( cnt * 4 - 4 ) ) & 0xF]; - append_ch( file, beg, end, ch ); - } - } else { - append_ch( file, beg, end, '0' ); - } - } - - static void append_ptr( FILE *const file, char **const beg, const char *const end, void *const p ) - { - append_uint( file, beg, end, uintptr_t( p ) ); - } - +#if defined(_WIN32) static void dump_to( const char *file ) { HANDLE handle = CreateFile( file, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, @@ -113,122 +51,7 @@ extern "C" { nullptr, nullptr, nullptr ); CloseHandle( handle ); } - - static void log_crash( const char *type, const char *msg ) - { - dump_to( ".core" ); - const char *crash_log_file = "config/crash.log"; - char *beg = buf, *end = buf + BUF_SIZE; - FILE *file = fopen( crash_log_file, "w" ); - append_str( file, &beg, end, "CRASH LOG FILE: " ); - append_str( file, &beg, end, crash_log_file ); - append_str( file, &beg, end, "\nVERSION: " ); - append_str( file, &beg, end, getVersionString() ); - append_str( file, &beg, end, "\nTYPE: " ); - append_str( file, &beg, end, type ); - append_str( file, &beg, end, "\nMESSAGE: " ); - append_str( file, &beg, end, msg ); - append_str( file, &beg, end, "\nSTACK TRACE:\n" ); - sym->SizeOfStruct = sizeof( SYMBOL_INFO ); - sym->MaxNameLen = MAX_NAME_LEN; - USHORT num_bt = CaptureStackBackTrace( 0, BT_CNT, bt, nullptr ); - HANDLE proc = GetCurrentProcess(); - for( USHORT i = 0; i < num_bt; ++i ) { - DWORD64 off; - append_str( file, &beg, end, " " ); - if( SymFromAddr( proc, reinterpret_cast( bt[i] ), &off, sym ) ) { - append_str( file, &beg, end, sym->Name ); - append_str( file, &beg, end, "+0x" ); - append_uint( file, &beg, end, off ); - } - append_str( file, &beg, end, "@0x" ); - append_ptr( file, &beg, end, bt[i] ); - DWORD64 mod_base = SymGetModuleBase64( proc, reinterpret_cast( bt[i] ) ); - if( mod_base ) { - append_ch( file, &beg, end, '[' ); - DWORD mod_len = GetModuleFileName( reinterpret_cast( mod_base ), mod_path, - MODULE_PATH_LEN ); - // mod_len == MODULE_NAME_LEN means insufficient buffer - if( mod_len > 0 && mod_len < MODULE_PATH_LEN ) { - const char *mod_name = mod_path + mod_len; - for( ; mod_name > mod_path && *( mod_name - 1 ) != '\\'; --mod_name ) { - } - append_str( file, &beg, end, mod_name ); - } else { - append_str( file, &beg, end, "0x" ); - append_uint( file, &beg, end, mod_base ); - } - append_str( file, &beg, end, "+0x" ); - append_uint( file, &beg, end, reinterpret_cast( bt[i] ) - mod_base ); - append_ch( file, &beg, end, ']' ); - } - append_ch( file, &beg, end, '\n' ); - } - *beg = '\0'; -#if defined(TILES) - if( SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR, "Error", buf, nullptr ) != 0 ) { - append_str( file, &beg, end, "Error creating SDL message box: " ); - append_str( file, &beg, end, SDL_GetError() ); - append_ch( file, &beg, end, '\n' ); - } #endif - if( file ) { - fclose( file ); - } - } - - static void signal_handler( int sig ) - { - // TODO: thread-safety? - // TODO: make string literals & static variables atomic? - signal( sig, SIG_DFL ); - // undefined behavior according to the standard - // but we can get nothing out of it without these - const char *msg; - switch( sig ) { - case SIGSEGV: - msg = "SIGSEGV: Segmentation fault"; - break; - case SIGILL: - msg = "SIGILL: Illegal instruction"; - break; - case SIGABRT: - msg = "SIGABRT: Abnormal termination"; - break; - case SIGFPE: - msg = "SIGFPE: Arithmetical error"; - break; - default: - return; - } - log_crash( "Signal", msg ); - // end of UB - std::signal( SIGABRT, SIG_DFL ); - abort(); - } - -} // extern "C" - -void init_crash_handlers() -{ - SymInitialize( GetCurrentProcess(), nullptr, TRUE ); - for( auto sig : { - SIGSEGV, SIGILL, SIGABRT, SIGFPE - } ) { - - std::signal( sig, signal_handler ); - } - std::set_terminate( crash_terminate_handler ); -} - -#else -// Non-Windows implementation - -#include - -#include "debug.h" - -extern "C" { static void log_crash( const char *type, const char *msg ) { @@ -236,6 +59,9 @@ extern "C" { // reasons, including the memory allocations and the SDL message box. // But it should usually work in practice, unless for example the // program segfaults inside malloc. +#if defined(_WIN32) + dump_to( ".core" ); +#endif const std::string crash_log_file = PATH_INFO::crash(); std::ostringstream log_text; log_text << "The program has crashed." @@ -290,22 +116,8 @@ extern "C" { #pragma GCC diagnostic pop abort(); } - } // extern "C" -void init_crash_handlers() -{ - for( auto sig : { - SIGSEGV, SIGILL, SIGABRT, SIGFPE - } ) { - - std::signal( sig, signal_handler ); - } - std::set_terminate( crash_terminate_handler ); -} - -#endif - [[noreturn]] static void crash_terminate_handler() { // TODO: thread-safety? @@ -321,6 +133,7 @@ void init_crash_handlers() } catch( const std::exception &e ) { type = typeid( e ).name(); msg = e.what(); + // call here to avoid `msg = e.what()` going out of scope log_crash( type, msg ); std::exit( EXIT_FAILURE ); } catch( ... ) { @@ -331,6 +144,17 @@ void init_crash_handlers() std::exit( EXIT_FAILURE ); } +void init_crash_handlers() +{ + for( auto sig : { + SIGSEGV, SIGILL, SIGABRT, SIGFPE + } ) { + + std::signal( sig, signal_handler ); + } + std::set_terminate( crash_terminate_handler ); +} + #else // !BACKTRACE void init_crash_handlers() diff --git a/src/debug.cpp b/src/debug.cpp index c898f192741c1..a0e1553289876 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -48,6 +48,9 @@ #if defined(BACKTRACE) # if defined(_WIN32) # include +# if defined(LIBBACKTRACE) +# include +# endif # else # include # include @@ -212,27 +215,6 @@ void limitDebugClass( int class_bitmask ) // Debug only {{{1 // --------------------------------------------------------------------- -#if defined(BACKTRACE) -#if defined(_WIN32) -constexpr int module_path_len = 512; -// on some systems the number of frames to capture have to be less than 63 according to the documentation -constexpr int bt_cnt = 62; -constexpr int max_name_len = 512; -// ( max_name_len - 1 ) because SYMBOL_INFO already contains a TCHAR -constexpr int sym_size = sizeof( SYMBOL_INFO ) + ( max_name_len - 1 ) * sizeof( TCHAR ); -static char mod_path[module_path_len]; -static PVOID bt[bt_cnt]; -static struct { - alignas( SYMBOL_INFO ) char storage[sym_size]; -} sym_storage; -static SYMBOL_INFO &sym = reinterpret_cast( sym_storage ); -#else -#define TRACE_SIZE 20 - -void *tracePtrs[TRACE_SIZE]; -#endif -#endif - // Debug Includes {{{2 // --------------------------------------------------------------------- @@ -578,25 +560,122 @@ static cata::optional debug_compute_load_offset( } #endif +#if defined(_WIN32) && defined(LIBBACKTRACE) +// wrap libbacktrace to use std::function instead of function pointers +using bt_error_callback = std::function; +using bt_full_callback = std::function; +using bt_syminfo_callback = std::function; + +static backtrace_state *bt_create_state( const char *const filename, const int threaded, + const bt_error_callback &cb ) +{ + return backtrace_create_state( filename, threaded, + []( void *const data, const char *const msg, const int errnum ) { + const bt_error_callback &cb = *reinterpret_cast( data ); + cb( msg, errnum ); + }, + const_cast( &cb ) ); +} + +static int bt_pcinfo( backtrace_state *const state, const uintptr_t pc, + const bt_full_callback &cb_full, const bt_error_callback &cb_error ) +{ + using cb_pair = std::pair; + cb_pair cb { cb_full, cb_error }; + return backtrace_pcinfo( state, pc, + // backtrace callback + []( void *const data, const uintptr_t pc, const char *const filename, + const int lineno, const char *const function ) -> int { + cb_pair &cb = *reinterpret_cast( data ); + return cb.first( pc, filename, lineno, function ); + }, + // error callback + []( void *const data, const char *const msg, const int errnum ) { + cb_pair &cb = *reinterpret_cast( data ); + cb.second( msg, errnum ); + }, + &cb ); +} + +static int bt_syminfo( backtrace_state *const state, const uintptr_t addr, + const bt_syminfo_callback &cb_syminfo, const bt_error_callback cb_error ) +{ + using cb_pair = std::pair; + cb_pair cb { cb_syminfo, cb_error }; + return backtrace_syminfo( state, addr, + // syminfo callback + []( void *const data, const uintptr_t pc, const char *const symname, + const uintptr_t symval, const uintptr_t symsize ) { + cb_pair &cb = *reinterpret_cast( data ); + cb.first( pc, symname, symval, symsize ); + }, + // error callback + []( void *const data, const char *const msg, const int errnum ) { + cb_pair &cb = *reinterpret_cast( data ); + cb.second( msg, errnum ); + }, + &cb ); +} +#endif + +#if defined(_WIN32) +class sym_init +{ + public: + sym_init() { + SymInitialize( GetCurrentProcess(), nullptr, TRUE ); + } + + ~sym_init() { + SymCleanup( GetCurrentProcess() ); + } +}; +static std::unique_ptr sym_init_; + +constexpr int module_path_len = 512; +// on some systems the number of frames to capture have to be less than 63 according to the documentation +constexpr int bt_cnt = 62; +constexpr int max_name_len = 512; +// ( max_name_len - 1 ) because SYMBOL_INFO already contains a TCHAR +constexpr int sym_size = sizeof( SYMBOL_INFO ) + ( max_name_len - 1 ) * sizeof( TCHAR ); +static char mod_path[module_path_len]; +static PVOID bt[bt_cnt]; +static struct { + alignas( SYMBOL_INFO ) char storage[sym_size]; +} sym_storage; +static SYMBOL_INFO &sym = reinterpret_cast( sym_storage ); +#if defined(LIBBACKTRACE) +static std::map bt_states; +#endif +#else +constexpr int bt_cnt = 20; +static void *bt[bt_cnt]; +#endif + void debug_write_backtrace( std::ostream &out ) { #if defined(_WIN32) + if( !sym_init_ ) { + sym_init_ = std::make_unique(); + } sym.SizeOfStruct = sizeof( SYMBOL_INFO ); sym.MaxNameLen = max_name_len; - USHORT num_bt = CaptureStackBackTrace( 0, bt_cnt, bt, nullptr ); - HANDLE proc = GetCurrentProcess(); + // libbacktrace's own backtrace capturing doesn't seem to work on Windows + const USHORT num_bt = CaptureStackBackTrace( 0, bt_cnt, bt, nullptr ); + const HANDLE proc = GetCurrentProcess(); for( USHORT i = 0; i < num_bt; ++i ) { DWORD64 off; - out << "\n ("; + out << "\n #" << i; + out << "\n (dbghelp: "; if( SymFromAddr( proc, reinterpret_cast( bt[i] ), &off, &sym ) ) { out << sym.Name << "+0x" << std::hex << off << std::dec; } out << "@" << bt[i]; - DWORD64 mod_base = SymGetModuleBase64( proc, reinterpret_cast( bt[i] ) ); + const DWORD64 mod_base = SymGetModuleBase64( proc, reinterpret_cast( bt[i] ) ); if( mod_base ) { out << "["; - DWORD mod_len = GetModuleFileName( reinterpret_cast( mod_base ), mod_path, - module_path_len ); + const DWORD mod_len = GetModuleFileName( reinterpret_cast( mod_base ), mod_path, + module_path_len ); // mod_len == module_path_len means insufficient buffer if( mod_len > 0 && mod_len < module_path_len ) { const char *mod_name = mod_path + mod_len; @@ -610,6 +689,67 @@ void debug_write_backtrace( std::ostream &out ) std::dec << "]"; } out << "), "; +#if defined(LIBBACKTRACE) + backtrace_state *bt_state = nullptr; + if( mod_base ) { + const auto it = bt_states.find( mod_base ); + if( it != bt_states.end() ) { + bt_state = it->second; + } else { + const DWORD mod_len = GetModuleFileName( reinterpret_cast( mod_base ), mod_path, + module_path_len ); + if( mod_len > 0 && mod_len < module_path_len ) { + bt_state = bt_create_state( mod_path, 0, + // error callback + [&out]( const char *const msg, const int errnum ) { + out << "\n (backtrace_create_state failed: errno = " << errnum + << ", msg = " << ( msg ? msg : "[no msg]" ) << "),"; + } ); + } else { + out << "\n (executable path exceeds " << module_path_len << " chars),"; + } + if( bt_state ) { + bt_states.emplace( mod_base, bt_state ); + } + } + } else { + out << "\n (unable to get module base address),"; + } + if( bt_state ) { + bt_syminfo( bt_state, reinterpret_cast( bt[i] ), + // syminfo callback + [&out]( const uintptr_t pc, const char *const symname, + const uintptr_t symval, const uintptr_t ) { + out << "\n (libbacktrace: " << ( symname ? symname : "[unknown symbol]" ) + << "+0x" << std::hex << pc - symval << std::dec + << "@0x" << std::hex << pc << std::dec + << "),"; + }, + // error callback + [&out]( const char *const msg, const int errnum ) { + out << "\n (backtrace_syminfo failed: errno = " << errnum + << ", msg = " << ( msg ? msg : "[no msg]" ) + << "),"; + } ); + bt_pcinfo( bt_state, reinterpret_cast( bt[i] ), + // backtrace callback + [&out]( const uintptr_t pc, const char *const filename, + const int lineno, const char *const function ) -> int { + out << "\n (libbacktrace: 0x" << std::hex << pc << std::dec + << " " << ( filename ? filename : "[unknown src]" ) + << ":" << lineno + << " " << ( function ? function : "[unknown func]" ) + << "),"; + return 0; + }, + // error callback + [&out]( const char *const msg, const int errnum ) { + out << "\n (backtrace_pcinfo failed: errno = " << errnum + << ", msg = " << ( msg ? msg : "[no msg]" ) + << "),"; + } ); + } +#endif } out << "\n"; #else @@ -617,8 +757,8 @@ void debug_write_backtrace( std::ostream &out ) // BACKTRACE is not supported under CYGWIN! ( void ) out; # else - int count = backtrace( tracePtrs, TRACE_SIZE ); - char **funcNames = backtrace_symbols( tracePtrs, count ); + int count = backtrace( bt, bt_cnt ); + char **funcNames = backtrace_symbols( bt, count ); for( int i = 0; i < count; ++i ) { out << "\n " << funcNames[i]; } @@ -684,7 +824,7 @@ void debug_write_backtrace( std::ostream &out ) // From that we need to extract the binary name, the symbol // name, and the offset within the symbol. We don't need to // extract the address (the last thing) because that's already - // available in tracePtrs. + // available in bt. auto funcName = funcNames[i]; assert( funcName ); // To appease static analysis @@ -719,7 +859,7 @@ void debug_write_backtrace( std::ostream &out ) cata::optional offset = debug_compute_load_offset( binary_name, symbol_name, offset_within_symbol, - tracePtrs[i], out ); + bt[i], out ); if( offset ) { load_offsets.emplace( binary_name, *offset ); } @@ -739,7 +879,7 @@ void debug_write_backtrace( std::ostream &out ) } last_binary_name = binary_name; - addresses.push_back( reinterpret_cast( tracePtrs[i] ) ); + addresses.push_back( reinterpret_cast( bt[i] ) ); } if( !addresses.empty() ) { diff --git a/src/faction_camp.cpp b/src/faction_camp.cpp index f991eb5a8de6b..6b646f4a569cc 100644 --- a/src/faction_camp.cpp +++ b/src/faction_camp.cpp @@ -1266,6 +1266,8 @@ void basecamp::get_available_missions( mission_data &mission_key ) "\n\nRisk: None\n" "Time: Ongoing" ) ); mission_key.add( "Assign Jobs", _( "Assign Jobs" ), entry ); + entry = _( "Notes:\nAbandon this camp" ); + mission_key.add( "Abandon Camp", _( "Abandon Camp" ), entry ); } // Missions assigned to the central tile that could be done by an expansion get_available_missions_by_dir( mission_key, base_camps::base_dir ); @@ -1319,6 +1321,9 @@ bool basecamp::handle_mission( const std::string &miss_id, cata::optional if( miss_id == "Assign Jobs" ) { job_assignment_ui(); } + if( miss_id == "Abandon Camp" ) { + abandon_camp(); + } if( miss_id == "Expand Base" ) { start_mission( "_faction_camp_expansion", 3_hours, true, @@ -1536,6 +1541,11 @@ void basecamp::start_upgrade( const std::string &bldg, const point &dir, if( making.requirements().can_make_with_inventory( _inv, making.get_component_filter(), 1 ) ) { bool must_feed = bldg != "faction_base_camp_1"; + basecamp_action_components components( making, 1, *this ); + if( !components.choose_components() ) { + return; + } + time_duration work_days = base_camps::to_workdays( making.batch_duration() ); npc_ptr comp = nullptr; if( making.required_skills.empty() ) { @@ -1554,13 +1564,34 @@ void basecamp::start_upgrade( const std::string &bldg, const point &dir, if( comp == nullptr ) { return; } - consume_components( making, 1 ); + components.consume_components(); update_in_progress( bldg, dir ); } else { popup( _( "You don't have the materials for the upgrade." ) ); } } +void basecamp::abandon_camp() +{ + validate_assignees(); + npc_ptr random_guy; + for( npc_ptr &guy : overmap_buffer.get_companion_mission_npcs( 10 ) ) { + npc_companion_mission c_mission = guy->get_companion_mission(); + if( c_mission.role_id != base_camps::id ) { + continue; + } + random_guy = guy; + const std::string return_msg = _( "responds to the emergency recall…" ); + finish_return( *guy, false, return_msg, "menial", 0, true ); + } + for( npc_ptr &guy : get_npcs_assigned() ) { + talk_function::stop_guard( *guy ); + } + overmap_buffer.remove_camp( *this ); + g->m.remove_submap_camp( random_guy->pos() ); + add_msg( m_info, _( "You abandon %s." ), name ); +} + void basecamp::job_assignment_ui() { int term_x = TERMY > FULL_SCREEN_HEIGHT ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; @@ -1945,11 +1976,17 @@ void basecamp::start_fortifications( std::string &bldg_exp ) return; } + const int batch_size = fortify_om.size() * 2 - 2; + basecamp_action_components components( making, batch_size, *this ); + if( !components.choose_components() ) { + return; + } + npc_ptr comp = start_mission( "_faction_camp_om_fortifications", total_time, true, _( "begins constructing fortifications…" ), false, {}, making.required_skills ); if( comp != nullptr ) { - consume_components( making, fortify_om.size() * 2 - 2 ); + components.consume_components(); comp->companion_mission_role_id = bldg_exp; for( auto pt : fortify_om ) { comp->companion_mission_points.push_back( pt ); @@ -2019,12 +2056,18 @@ void basecamp::start_crafting( const std::string &cur_id, const point &cur_dir, popup( _( "Your batch is too large!" ) ); return; } + + basecamp_action_components components( making, batch_size, *this ); + if( !components.choose_components() ) { + return; + } + time_duration work_days = base_camps::to_workdays( making.batch_duration( batch_size ) ); npc_ptr comp = start_mission( miss_id + cur_dir_id, work_days, true, _( "begins to work…" ), false, {}, making.required_skills ); if( comp != nullptr ) { - consume_components( making, batch_size ); + components.consume_components(); for( const item &results : making.create_results( batch_size ) ) { comp->companion_mission_inv.add_item( results ); } diff --git a/src/magic.cpp b/src/magic.cpp index 0ad585519c369..c0fe5b02a1eec 100644 --- a/src/magic.cpp +++ b/src/magic.cpp @@ -97,6 +97,7 @@ std::string enum_to_string( spell_flag data ) case spell_flag::NO_HANDS: return "NO_HANDS"; case spell_flag::NO_LEGS: return "NO_LEGS"; case spell_flag::UNSAFE_TELEPORT: return "UNSAFE_TELEPORT"; + case spell_flag::SWAP_POS: return "SWAP_POS"; case spell_flag::CONCENTRATE: return "CONCENTRATE"; case spell_flag::RANDOM_AOE: return "RANDOM_AOE"; case spell_flag::RANDOM_DAMAGE: return "RANDOM_DAMAGE"; @@ -248,6 +249,10 @@ void spell_type::load( const JsonObject &jo, const std::string & ) const auto effect_targets_reader = enum_flags_reader { "effect_targets" }; optional( jo, was_loaded, "effect_filter", effect_targets, effect_targets_reader ); + const auto targeted_monster_ids_reader = auto_flags_reader {}; + optional( jo, was_loaded, "targeted_monster_ids", targeted_monster_ids, + targeted_monster_ids_reader ); + const auto trigger_reader = enum_flags_reader { "valid_targets" }; mandatory( jo, was_loaded, "valid_targets", valid_targets, trigger_reader ); @@ -895,6 +900,7 @@ bool spell::is_valid_target( const Creature &caster, const tripoint &p ) const valid = valid || ( cr_att == Creature::A_FRIENDLY && is_valid_target( target_ally ) && p != caster.pos() ); valid = valid || ( is_valid_target( target_self ) && p == caster.pos() ); + valid = valid && target_by_monster_id( p ); } else { valid = is_valid_target( target_ground ); } @@ -906,6 +912,20 @@ bool spell::is_valid_effect_target( valid_target t ) const return type->effect_targets[t]; } +bool spell::target_by_monster_id( const tripoint &p ) const +{ + if( type->targeted_monster_ids.empty() ) { + return true; + } + bool valid = false; + if( monster *const target = g->critter_at( p ) ) { + if( type->targeted_monster_ids.find( target->type->id ) != type->targeted_monster_ids.end() ) { + valid = true; + } + } + return valid; +} + std::string spell::description() const { return type->description.translated(); diff --git a/src/magic.h b/src/magic.h index 32dc8d1e86328..fa5a15ba0e127 100644 --- a/src/magic.h +++ b/src/magic.h @@ -35,6 +35,7 @@ template struct enum_traits; enum spell_flag { PERMANENT, // items or creatures spawned with this spell do not disappear and die as normal IGNORE_WALLS, // spell's aoe goes through walls + SWAP_POS, // a projectile spell swaps the positions of the caster and target HOSTILE_SUMMON, // summon spell always spawns a hostile monster HOSTILE_50, // summoned monster spawns friendly 50% of the time SILENT, // spell makes no noise at target @@ -245,6 +246,8 @@ class spell_type // list of valid targets enum enum_bitset valid_targets; + std::set targeted_monster_ids; + // lits of bodyparts this spell applies its effect to enum_bitset affected_bps; @@ -400,6 +403,7 @@ class spell bool is_valid_target( const Creature &caster, const tripoint &p ) const; bool is_valid_target( valid_target t ) const; bool is_valid_effect_target( valid_target t ) const; + bool target_by_monster_id( const tripoint &p ) const; // picks a random valid tripoint from @area cata::optional random_valid_target( const Creature &caster, diff --git a/src/magic_spell_effect.cpp b/src/magic_spell_effect.cpp index c6fac1357fcf4..f31dd3a640b85 100644 --- a/src/magic_spell_effect.cpp +++ b/src/magic_spell_effect.cpp @@ -112,6 +112,15 @@ void spell_effect::teleport_random( const spell &sp, Creature &caster, const tri teleport::teleport( caster, min_distance, max_distance, safe, false ); } +static void swap_pos( Creature &caster, const tripoint &target ) +{ + Creature *const critter = g->critter_at( target ); + critter->setpos( caster.pos() ); + caster.setpos( target ); + //update map in case a monster swapped positions with the player + g->update_map( g->u ); +} + void spell_effect::pain_split( const spell &sp, Creature &caster, const tripoint & ) { player *p = caster.as_player(); @@ -447,6 +456,9 @@ void spell_effect::target_attack( const spell &sp, Creature &caster, { damage_targets( sp, caster, spell_effect_area( sp, epicenter, spell_effect_blast, caster, sp.has_flag( spell_flag::IGNORE_WALLS ) ) ); + if( sp.has_flag( spell_flag::SWAP_POS ) ) { + swap_pos( caster, epicenter ); + } } void spell_effect::cone_attack( const spell &sp, Creature &caster, diff --git a/src/main_menu.cpp b/src/main_menu.cpp index 3b82ff511309f..52975a0ad5929 100644 --- a/src/main_menu.cpp +++ b/src/main_menu.cpp @@ -41,7 +41,7 @@ #define dbg(x) DebugLog((DebugLevel)(x),D_GAME) << __FILE__ << ":" << __LINE__ << ": " -static const holiday current_holiday = holiday::new_year; +static const holiday current_holiday = holiday::none; void main_menu::on_move() const { diff --git a/src/npctalk.cpp b/src/npctalk.cpp index b0fa2e0c49064..ac411410b7521 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -2571,6 +2571,7 @@ void talk_effect_t::parse_string_effect( const std::string &effect_id, const Jso WRAP( do_farming ), WRAP( assign_guard ), WRAP( assign_camp ), + WRAP( abandon_camp ), WRAP( stop_guard ), WRAP( start_camp ), WRAP( buy_cow ), diff --git a/src/npctalk.h b/src/npctalk.h index 0debe5e30486d..79da5d35ac5e0 100644 --- a/src/npctalk.h +++ b/src/npctalk.h @@ -51,6 +51,7 @@ void goto_location( npc & ); void assign_base( npc & ); void assign_guard( npc & ); void assign_camp( npc & ); +void abandon_camp( npc & ); void stop_guard( npc & ); void end_conversation( npc & ); void insult_combat( npc & ); diff --git a/src/npctalk_funcs.cpp b/src/npctalk_funcs.cpp index b9f3bed282182..256c59fd343fc 100644 --- a/src/npctalk_funcs.cpp +++ b/src/npctalk_funcs.cpp @@ -346,6 +346,15 @@ void talk_function::assign_guard( npc &p ) p.set_omt_destination(); } +void talk_function::abandon_camp( npc &p ) +{ + cata::optional bcp = overmap_buffer.find_camp( p.global_omt_location().xy() ); + if( bcp ) { + basecamp *temp_camp = *bcp; + temp_camp->abandon_camp(); + } +} + void talk_function::assign_camp( npc &p ) { cata::optional bcp = overmap_buffer.find_camp( p.global_omt_location().xy() ); diff --git a/src/overmap.cpp b/src/overmap.cpp index 7190820786637..34268bb425814 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -471,17 +471,17 @@ bool is_river_or_lake( const oter_id &ter ) bool is_ot_match( const std::string &name, const oter_id &oter, const ot_match_type match_type ) { - const auto is_ot = []( const std::string & otype, const oter_id & oter ) { + static const auto is_ot = []( const std::string & otype, const oter_id & oter ) { return otype == oter.id().str(); }; - const auto is_ot_type = []( const std::string & otype, const oter_id & oter ) { + static const auto is_ot_type = []( const std::string & otype, const oter_id & oter ) { // Is a match if the base type is the same which will allow for handling rotations/linear features // but won't incorrectly match other locations that happen to contain the substring. return otype == oter->get_type_id().str(); }; - const auto is_ot_prefix = []( const std::string & otype, const oter_id & oter ) { + static const auto is_ot_prefix = []( const std::string & otype, const oter_id & oter ) { const size_t oter_size = oter.id().str().size(); const size_t compare_size = otype.size(); if( compare_size > oter_size ) { @@ -502,7 +502,7 @@ bool is_ot_match( const std::string &name, const oter_id &oter, return oter_str.str()[compare_size] == '_'; }; - const auto is_ot_subtype = []( const std::string & otype, const oter_id & oter ) { + static const auto is_ot_subtype = []( const std::string & otype, const oter_id & oter ) { // Checks for any partial match. return strstr( oter.id().c_str(), otype.c_str() ); }; @@ -1534,13 +1534,10 @@ bool overmap::generate_sub( const int z ) } else if( oter_above == "cave_rat" && z == -2 ) { ter_set( p, oter_id( "cave_rat" ) ); } else if( oter_above == "anthill" || oter_above == "acid_anthill" ) { - mongroup_id ant_group( oter_above == "anthill" ? "GROUP_ANT" : "GROUP_ANT_ACID" ); - int size = rng( MIN_ANT_SIZE, MAX_ANT_SIZE ); + const int size = rng( MIN_ANT_SIZE, MAX_ANT_SIZE ); ant_points.push_back( city( p.xy(), size ) ); - add_mon_group( mongroup( ant_group, tripoint( i * 2, j * 2, z ), - ( size * 3 ) / 2, rng( 6000, 8000 ) ) ); } else if( oter_above == "slimepit_down" ) { - int size = rng( MIN_GOO_SIZE, MAX_GOO_SIZE ); + const int size = rng( MIN_GOO_SIZE, MAX_GOO_SIZE ); goo_points.push_back( city( p.xy(), size ) ); } else if( oter_above == "forest_water" ) { ter_set( p, oter_id( "cavern" ) ); @@ -1586,10 +1583,6 @@ bool overmap::generate_sub( const int z ) const string_id sewer_tunnel( "sewer_tunnel" ); connect_closest_points( sewer_points, z, *sewer_tunnel ); - for( auto &i : ant_points ) { - build_anthill( tripoint( i.pos, z ), i.size ); - } - // A third of overmaps have labs with a 1-in-2 chance of being subway connected. // If the central lab exists, all labs which go down to z=4 will have a subway to central. int lab_train_odds = 0; @@ -1735,6 +1728,17 @@ bool overmap::generate_sub( const int z ) ter_set( tripoint( i, z ), oter_id( "mine_shaft" ) ); requires_sub = true; } + for( auto &i : ant_points ) { + if( ter( { i.pos, z } ) != "empty_rock" ) { + continue; + } + mongroup_id ant_group( ter( i.pos + tripoint_above ) == "anthill" ? + "GROUP_ANT" : "GROUP_ANT_ACID" ); + add_mon_group( mongroup( ant_group, tripoint( i.pos.x * 2, i.pos.y * 2, z ), + ( i.size * 3 ) / 2, rng( 6000, 8000 ) ) ); + build_anthill( tripoint( i.pos, z ), i.size ); + } + return requires_sub; } @@ -3165,6 +3169,8 @@ void overmap::build_anthill( const tripoint &p, int s ) build_tunnel( p, s - rng( 0, 3 ), dir ); } + // @TODO: This should follow the tunnel network, + // as of now it can pick a tile from an adjacent ant network. std::vector queenpoints; for( int i = -s; i <= s; i++ ) { for( int j = -s; j <= s; j++ ) { @@ -3175,7 +3181,7 @@ void overmap::build_anthill( const tripoint &p, int s ) } } if( queenpoints.empty() ) { - debugmsg( "No queenpoints when building anthill" ); + debugmsg( "No queenpoints when building anthill, anthill over %s", ter( p ).id().str() ); } const tripoint target = random_entry( queenpoints ); ter_set( target, oter_id( "ants_queen" ) ); @@ -3192,7 +3198,7 @@ void overmap::build_anthill( const tripoint &p, int s ) const oter_id &oter = ter( root ); for( auto dir : om_direction::all ) { const tripoint p = root + om_direction::displace( dir ); - if( check_ot( "ants", ot_match_type::type, p ) ) { + if( check_ot( "ants", ot_match_type::prefix, p ) ) { size_t line = oter->get_line(); line = om_lines::set_segment( line, dir ); if( line != oter->get_line() ) { @@ -3215,11 +3221,13 @@ void overmap::build_tunnel( const tripoint &p, int s, om_direction::type dir ) } const oter_id root_id( "ants_isolated" ); - if( check_ot( "ants", ot_match_type::type, p ) && root_id != ter( p )->id ) { - return; - } - if( !is_ot_match( "empty_rock", ter( p )->id, ot_match_type::type ) ) { - return; + if( root_id != ter( p )->id ) { + if( check_ot( "ants", ot_match_type::type, p ) ) { + return; + } + if( !is_ot_match( "empty_rock", ter( p ), ot_match_type::type ) ) { + return; + } } ter_set( p, oter_id( root_id ) ); @@ -3229,7 +3237,7 @@ void overmap::build_tunnel( const tripoint &p, int s, om_direction::type dir ) for( auto r : om_direction::all ) { const tripoint cand = p + om_direction::displace( r ); if( !check_ot( "ants", ot_match_type::type, cand ) && - !is_ot_match( "empty_rock", ter( cand )->id, ot_match_type::type ) ) { + is_ot_match( "empty_rock", ter( cand ), ot_match_type::type ) ) { valid.push_back( r ); } } diff --git a/src/overmapbuffer.cpp b/src/overmapbuffer.cpp index bccaff5c8395b..8200154ca4e6c 100644 --- a/src/overmapbuffer.cpp +++ b/src/overmapbuffer.cpp @@ -1089,11 +1089,11 @@ std::vector overmapbuffer::get_overmaps_near( const point &p, const i return get_overmaps_near( tripoint( p, 0 ), radius ); } -std::vector> overmapbuffer::get_companion_mission_npcs() +std::vector> overmapbuffer::get_companion_mission_npcs( int range ) { std::vector> available; // TODO: this is an arbitrary radius, replace with something sane. - for( const auto &guy : get_npcs_near_player( 100 ) ) { + for( const auto &guy : get_npcs_near_player( range ) ) { if( guy->has_companion_mission() ) { available.push_back( guy ); } diff --git a/src/overmapbuffer.h b/src/overmapbuffer.h index 7f8a84d07b84a..274796fe0b57f 100644 --- a/src/overmapbuffer.h +++ b/src/overmapbuffer.h @@ -233,7 +233,7 @@ class overmapbuffer * Get all (currently loaded!) npcs that have a companion * mission set. */ - std::vector> get_companion_mission_npcs(); + std::vector> get_companion_mission_npcs( int range = 100 ); /** * Uses overmap terrain coordinates, this also means radius is * in overmap terrain. diff --git a/src/visitable.cpp b/src/visitable.cpp index 343d4b3641bff..607c2589c9dc9 100644 --- a/src/visitable.cpp +++ b/src/visitable.cpp @@ -581,6 +581,10 @@ std::list visitable::remove_items_with( const ++stack; } } + + // Invalidate binning cache + inv->binned = false; + return res; } diff --git a/tests/visitable_remove.cpp b/tests/visitable_remove.cpp index 78833a83b89de..a12f5aba9c730 100644 --- a/tests/visitable_remove.cpp +++ b/tests/visitable_remove.cpp @@ -487,3 +487,16 @@ TEST_CASE( "visitable_remove", "[visitable]" ) } } } + +TEST_CASE( "inventory_remove_invalidates_binning_cache", "[visitable][inventory]" ) +{ + inventory inv; + std::list items = { item( "bone" ) }; + inv += items; + CHECK( inv.charges_of( "bone" ) == 1 ); + inv.remove_items_with( return_true ); + CHECK( inv.size() == 0 ); + // The following used to be a heap use-after-free due to a caching bug. + // Now should be safe. + CHECK( inv.charges_of( "bone" ) == 0 ); +}