Skip to content

Commit

Permalink
support B42.4 new foraging zones
Browse files Browse the repository at this point in the history
  • Loading branch information
cff29546 committed Mar 8, 2025
1 parent 4ecbaa6 commit 205d51c
Show file tree
Hide file tree
Showing 11 changed files with 313 additions and 145 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pzmap2dzi is a command-line tool running on Windows to convert Project Zomboid m
- I18n support
- Multi-thread acceleration
- Tested with game version 41.78.16 and 42.0.2 UNSTABLE on both python 2.7 and python 3.11
- see [change log](./docs/change_log.md) for more updates

# Requirement
- **Storage**: The full output size of isometric map for game version 41.78 is around 450GB (or 2.5TB with lossless png format) and consists of 4M files. SSD is recommended as high I/O bandwidth can reduce render time.
Expand Down
4 changes: 2 additions & 2 deletions VERSION
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
pzmap2dzi main.py 1.0.3
html 1.0.2
pzmap2dzi main.py 1.0.4
html 1.0.4
53 changes: 50 additions & 3 deletions conf/conf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,56 @@ render_conf:
zombie_count_font_size: 40

# objects areas
vehicle: true
special_zombie: true
story: true
# objects font settings, using default font if omitted
# objects_font: arial.ttf
# objects_font_size: 20

# foraging & objects color config
# Possible color value are CSS3-style color specifiers.
# For more details, see:
# https://pillow.readthedocs.io/en/stable/reference/ImageColor.html
#
# If the value doesn't provide alpha, default alpha is set:
# For foraging default alpha = 128 (50%)
# For objects default alpha = 255 (100%)
#
# To skip render of a type, set color to 'skip'
#
# Example values:
# red
# '#FF0000'
# ‘#FF000080’
# 'rgba(255, 0, 0, 128)'
# 'rgb(255, 0, 0)'
# 'hsl(0, 100%, 50%)'
#
foraging_color_default: Gray
foraging_color:
Nav: White
TownZone: Blue
TrailerPark: Cyan
Vegitation: Yellow
Forest: Lime
DeepForest: Green
FarmLand: Magenta
Farm: Red
ForagingNav: White # B42 Road
Water: DeepSkyBlue # B42
WaterNoFish: SlateGrey # B42
PHForest: OrangeRed # B42.4 Acidic Forest
PHMixForest: Orange # B42.4 Acidic Mixed Forest
PRForest: ForestGreen # B42.4 Primary Forest
FarmMixForest: Olive # B42.4 Farmland Forest
FarmForest: Orange # B42.4 Managed Forestry
BirchForest: OliveDrab # B42.4 Birch Forest
BirchMixForest: DarkOliveGreen # B42.4 Birch Mixed Forest
OrganicForest: LawnGreen # B42.4 Organic Forest

objects_color_default: White
objects_color:
# Special Zombie Spawn Area
ZombiesType: Red
# Car Spawn Area
ParkingStall: Blue
# Zone Story
ZoneStory: Yellow
11 changes: 11 additions & 0 deletions docs/change_log.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Change log

# 2025-03-08: 1.0.4 + UI 1.0.4

* Support B42.4 foraging zones
* Customizable colors for foraging and objects

# 2025-02-12: 1.0.3 + UI 1.0.2

* B42 support
* .pzby basement file parser
59 changes: 34 additions & 25 deletions html/pzmap.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,30 @@ var pmodules = [

window.addEventListener("keydown", (event) => {onKeyDown(event);});

var LEGEND_TEMPLATE = {
foraging: '<div class="legend" style="background-color:{color}"></div><span id="{id}"></span>',
objects: '<div class="legend" style="border-color:{color}; border-width: 3px;"></div><span id="{id}"></span>'
};
function genLegendsUI(type, mapping) {
let label_id = type + '_legends_text';
let id = [label_id];
let ui = '<b id="' + label_id + '"></b>';

template = LEGEND_TEMPLATE[type];
if (template) {
for (let key in mapping) {
let color = mapping[key];
if (color == 'skip') {
continue;
}
let legend_id = type + '_legend_' + key;
ui += util.format(template, {color: color, id: legend_id});
id.push(legend_id);
}
}
return [id, ui];
}

function initUI_HTML() {
g.UI_HTML = {};
g.UI_ID = {};
Expand All @@ -51,34 +75,19 @@ function initUI_HTML() {
<div id="map_output" style="display: inline-block"></div>`;
g.UI_ID.map = ['map_all_btn', 'map_selector_dummy_option', 'map_loaded_text'];

g.UI_HTML.foraging = `
<b id="foraging_legends_text"></b>
<div class="legend" style="background-color:#fff"></div><span id="nav"></span>
<div class="legend" style="background-color:#00f"></div><span id="town_zone"></span>
<div class="legend" style="background-color:#0ff"></div><span id="trailer_park"></span>
<div class="legend" style="background-color:#ff0"></div><span id="vegitation"></span>
<div class="legend" style="background-color:#0f0"></div><span id="forest"></span>
<div class="legend" style="background-color:#080"></div><span id="deep_forest"></span>
<div class="legend" style="background-color:#f0f"></div><span id="farmland"></span>
<div class="legend" style="background-color:#f00"></div><span id="farm"></span>`;
if (g.base_map.pz_version === 'B42') {
g.UI_HTML.foraging += `
<div class="legend" style="background-color:#00bfff"></div><span id="water"></span>
<div class="legend" style="background-color:#708090"></div><span id="water_no_fish"></span>`;
let legends;
legends = util.getByPath(g, 'base_map', 'info', 'foraging', 'legends');
if (!legends) {
legends = {Nav: 'White', TownZone: 'Blue', TrailerPark: 'Cyan', Vegitation: 'Yellow', Forest: 'Lime', DeepForest: 'Green', FarmLand: 'Magenta', Farm: 'Red'}
}
[g.UI_ID.foraging, g.UI_HTML.foraging] = genLegendsUI('foraging', legends);
g.UI_HTML.foraging += `<span>&emsp; &emsp;</span>`;

g.UI_ID.foraging = [
'foraging_legends_text', 'nav', 'town_zone', 'trailer_park',
'vegitation', 'forest', 'deep_forest', 'farmland', 'farm',
'water', 'water_no_fish'];

g.UI_HTML.objects = `
<b id="objects_legends_text"></b>
<div class="legend" style="border-color:#f00; border-width: 3px;"></div><span id="zombie_type"></span>
<div class="legend" style="border-color:#00f; border-width: 3px;"></div><span id="parking_stall"></span>
<div class="legend" style="border-color:#ff0; border-width: 3px;"></div><span id="zone_story"></span>`;
g.UI_ID.objects = [ 'objects_legends_text', 'zombie_type', 'parking_stall', 'zone_story']
legends = util.getByPath(g, 'base_map', 'info', 'objects', 'legends');
if (!legends) {
legends = {ZombiesType: 'Red', ParkingStall: 'Blue', ZoneStory: 'Yellow'}
}
[g.UI_ID.objects, g.UI_HTML.objects] = genLegendsUI('objects', legends);

g.UI_HTML.marker = `
<div style="display: flex">
Expand Down
123 changes: 84 additions & 39 deletions html/pzmap/i18n/i18n.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,36 +47,63 @@ template:
ForagingLegends:
en: 'Foraging Legends:'
cn: '搜寻区域图例:'
Road:
LegendNav:
en: 'Road'
cn: '道路'
TownZone:
LegendTownZone:
en: 'Urban Area'
cn: '市区'
TrailerPark:
LegendTrailerPark:
en: 'Trailer Park'
cn: '拖车公园'
Vegitation:
LegendVegitation:
en: 'Vegitation'
cn: '草地'
Forest:
LegendForest:
en: 'Forest'
cn: '森林'
DeepForest:
LegendDeepForest:
en: 'Deep Forest'
cn: '深林'
Farmland:
LegendFarmLand:
en: 'Farmland'
cn: '农田'
Farm:
LegendFarm:
en: 'Farm'
cn: '农场'
Water:
LegendForagingNav:
en: 'Road'
cn: '道路'
LegendWater:
en: 'Water'
cn: '水域'
WaterNoFish:
LegendWaterNoFish:
en: 'Water (No Fish)'
cn: '水域(不可钓鱼)'
LegendPHForest:
en: 'Acidic Forest'
cn: '酸性林'
LegendPHMixForest:
en: 'Acidic Mixed Forest'
cn: '酸性混交林'
LegendPRForest:
en: 'Primary Forest'
cn: '原始林'
LegendFarmMixForest:
en: 'Farmland Forest'
cn: '农田林'
LegendFarmForest:
en: 'Managed Forestry'
cn: '人工林'
LegendBirchForest:
en: 'Birch Forest'
cn: '桦木林'
LegendBirchMixForest:
en: 'Birch Mixed Forest'
cn: '桦木混交林'
LegendOrganicForest:
en: 'Organic Forest'
cn: '有机林'
RoomButton:
en: 'Room'
cn: '房间定义'
Expand All @@ -86,13 +113,13 @@ template:
ObjectsLegends:
en: 'Objects Legends:'
cn: '随机事件图例:'
ZombieType:
LegendZombiesType:
en: 'Zombie Type'
cn: '特殊僵尸'
ParkingStall:
LegendParkingStall:
en: 'Car Spawn'
cn: '车辆生成'
ZoneStory:
LegendZoneStory:
en: 'Zone Story'
cn: '区域故事'
MarkerButton:
Expand Down Expand Up @@ -401,38 +428,56 @@ mapping:
innerHTML: ForagingButton
foraging_legends_text:
innerHTML: ForagingLegends
nav:
innerHTML: Road
town_zone:
innerHTML: TownZone
trailer_park:
innerHTML: TrailerPark
vegitation:
innerHTML: Vegitation
forest:
innerHTML: Forest
deep_forest:
innerHTML: DeepForest
farmland:
innerHTML: Farmland
farm:
innerHTML: Farm
water:
innerHTML: Water
water_no_fish:
innerHTML: WaterNoFish
foraging_legend_Nav:
innerHTML: LegendNav
foraging_legend_TownZone:
innerHTML: LegendTownZone
foraging_legend_TrailerPark:
innerHTML: LegendTrailerPark
foraging_legend_Vegitation:
innerHTML: LegendVegitation
foraging_legend_Forest:
innerHTML: LegendForest
foraging_legend_DeepForest:
innerHTML: LegendDeepForest
foraging_legend_FarmLand:
innerHTML: LegendFarmLand
foraging_legend_Farm:
innerHTML: LegendFarm
foraging_legend_ForagingNav:
innerHTML: LegendForagingNav
foraging_legend_Water:
innerHTML: LegendWater
foraging_legend_WaterNoFish:
innerHTML: LegendWaterNoFish
foraging_legend_PHForest:
innerHTML: LegendPHForest
foraging_legend_PHMixForest:
innerHTML: LegendPHMixForest
foraging_legend_PRForest:
innerHTML: LegendPRForest
foraging_legend_FarmMixForest:
innerHTML: LegendFarmMixForest
foraging_legend_FarmForest:
innerHTML: LegendFarmForest
foraging_legend_BirchForest:
innerHTML: LegendBirchForest
foraging_legend_BirchMixForest:
innerHTML: LegendBirchMixForest
foraging_legend_OrganicForest:
innerHTML: LegendOrganicForest
room_btn:
innerHTML: RoomButton
objects_btn:
innerHTML: ObjectsButton
objects_legends_text:
innerHTML: ObjectsLegends
zombie_type:
innerHTML: ZombieType
parking_stall:
innerHTML: ParkingStall
zone_story:
innerHTML: ZoneStory
objects_legend_ZombiesType:
innerHTML: LegendZombiesType
objects_legend_ParkingStall:
innerHTML: LegendParkingStall
objects_legend_ZoneStory:
innerHTML: LegendZoneStory
marker_btn:
innerHTML: MarkerButton
marker_save_btn:
Expand Down
12 changes: 11 additions & 1 deletion html/pzmap/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export function parseJson(data) {

export function format(template, args) {
let formatted = template;
for( var arg in args ) {
for(let arg in args) {
formatted = formatted.replace("{" + arg + "}", args[arg]);
}
return formatted;
Expand All @@ -115,3 +115,13 @@ export function format(template, args) {
export function isObject(o) {
return (typeof o === 'object' && !Array.isArray(o) && o !== null);
}

export function getByPath(o, ...args) {
for (let key of args) {
if (o === undefined || o === null) {
return o;
}
o = o[key];
}
return o;
}
20 changes: 19 additions & 1 deletion pzmap2dzi/pzdzi.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,24 @@ def save_map_info(self):
info = self.update_map_info(info)
path = os.path.join(self.path, 'map_info.json')

# dump and compact list values
data = json.dumps(info, indent=1)
data = data.replace('\n ', '').replace('\n ]', ']').replace('[ ', '[')
level = 0
output = []
for c in data:
if c == '[':
level += 1
elif c == ']':
level -= 1
elif c in ' \n':
if level:
continue
elif c == ',':
output.append(', ')
continue
output.append(c)
data = ''.join(output)

with open(path, 'w') as f:
f.write(data)

Expand Down Expand Up @@ -319,6 +335,7 @@ def pz_init(self, path, **options):
self.minlayer = version_info['minlayer']
self.maxlayer = version_info['maxlayer']
self.pzmap2dzi_version = options.get('pzmap2dzi_version', 'unknown')
self.legends = options.get('legends', {})
layer_range = options.get('layer_range', 'all')
if layer_range != 'all':
self.minlayer = max(self.minlayer, layer_range[0])
Expand All @@ -342,6 +359,7 @@ def update_pz_map_info(self, info):
info['maxlayer'] = self.maxlayer
info['minlayer'] = self.minlayer
info['pzmap2dzi_version'] = self.pzmap2dzi_version
info['legends'] = self.legends
return info


Expand Down
Loading

0 comments on commit 205d51c

Please sign in to comment.