Files
mtgodot-poc/tools/server/npc-shops/install.sh
T
shenleiandClaude Opus 5.5 54fa2c0fc3 npc-shops: generic NPC shop installer + mount shop 15 on NPC 20368
tools/server/item-mall-shop becomes tools/server/npc-shops with one
directory per shop (shop.conf + items.tsv) and install.sh <shop dir>.
New mount shop: 35 ride tickets on NPC 20368 (renamed 坐骑商人 via
NPC_NAME -> mob_names.txt) beside the stable boy in a1/b1/c1. Verified
on 203: 35 slots at the drafted prices, bought + used 71114 -> mounted.
zh overlay: 71118 虎坐骑券(黄), 20368 坐骑商人.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:38:37 +09:00

77 lines
3.6 KiB
Bash
Executable File

#!/bin/sh
# Installs one NPC shop (README.md): sh install.sh <shop dir>, where the directory has shop.conf (the shop,
# its NPC and where the NPC stands) and items.tsv (what it sells, at which price). Run on the server, then
# restart db + game. Safe to run again: prices and the shop are rewritten from items.tsv, the NPC is only
# added to a village that does not have one yet.
set -eu
[ $# -eq 1 ] || { echo "usage: sh install.sh <shop dir>" >&2; exit 2; }
SHOP_DIR=$(cd "$1" && pwd)
SERVER=${SERVER:-/usr/metin2/server}
LOCALE=${LOCALE:-newcibn}
ITEMS="$SHOP_DIR/items.tsv"
PROTO="$SERVER/share/conf/item_proto.txt"
MOB_PROTO="$SERVER/share/conf/mob_proto.txt"
MAPS="$SERVER/share/locale/$LOCALE/map"
export LC_ALL=C
# SHOP_VNUM, SHOP_NAME, NPC_VNUM, VILLAGES (one "map x y facing" line per village) and optionally NPC_NAME
# (UTF-8), the name shown over the NPC.
NPC_NAME=
. "$SHOP_DIR/shop.conf"
MOB_NAMES="$SERVER/share/conf/mob_names.txt"
BACKUP=/root/backup-npcshop/$SHOP_NAME-$(date +%Y%m%d-%H%M%S)
mkdir -p "$BACKUP"
cp -p "$PROTO" "$BACKUP/item_proto.txt"
cp -p "$MOB_PROTO" "$BACKUP/mob_proto.txt"
cp -p "$MOB_NAMES" "$BACKUP/mob_names.txt"
echo "$VILLAGES" | while read -r map x y dir; do cp -p "$MAPS/$map/npc.txt" "$BACKUP/$map.npc.txt"; done
mysqldump -uroot player shop shop_item item_proto mob_proto > "$BACKUP/player-shop.sql"
echo "backup: $BACKUP"
# item_proto.txt column 10 is the price an NPC shop sells the item for (TItemTable::dwGold).
awk -F'\t' -v OFS='\t' 'NR == FNR { if ($1 !~ /^#/ && NF >= 3) { price[$1] = $3; want++ } next }
($1 in price) { $10 = price[$1]; n++ } { print }
END { if (n != want) { print "item_proto.txt: " n " of " want " items found" > "/dev/stderr"; exit 1 } }' \
"$ITEMS" "$PROTO" > "$BACKUP/item_proto.new"
cat "$BACKUP/item_proto.new" > "$PROTO"
# mob_proto.txt column 14 is ON_CLICK: the NPC only opens its shop with 1 (ON_CLICK_SHOP, trigger.cpp);
# 9010 ships with 2, which has no handler.
awk -F'\t' -v OFS='\t' -v v=$NPC_VNUM '$1 == v { $14 = 1; n++ } { print }
END { if (n != 1) { print "mob_proto.txt: NPC " v " not found" > "/dev/stderr"; exit 1 } }' \
"$MOB_PROTO" > "$BACKUP/mob_proto.new"
cat "$BACKUP/mob_proto.new" > "$MOB_PROTO"
# mob_names.txt is in the locale's code page (GB2312 for newcibn).
if [ -n "$NPC_NAME" ]; then
name=$(printf '%s' "$NPC_NAME" | iconv -f UTF-8 -t GB2312)
awk -F'\t' -v OFS='\t' -v v=$NPC_VNUM -v name="$name" '$1 == v { $2 = name; n++ } { print }
END { if (n != 1) { print "mob_names.txt: NPC " v " not found" > "/dev/stderr"; exit 1 } }' \
"$MOB_NAMES" > "$BACKUP/mob_names.new"
cat "$BACKUP/mob_names.new" > "$MOB_NAMES"
fi
{
awk -F'\t' '$1 !~ /^#/ && NF >= 3 { printf "UPDATE item_proto SET gold = %d WHERE vnum = %d;\n", $3, $1 }' "$ITEMS"
echo "UPDATE mob_proto SET on_click = 1 WHERE vnum = $NPC_VNUM;"
echo "REPLACE INTO shop (vnum, name, npc_vnum) VALUES ($SHOP_VNUM, '$SHOP_NAME', $NPC_VNUM);"
echo "DELETE FROM shop_item WHERE shop_vnum = $SHOP_VNUM;"
awk -F'\t' -v shop=$SHOP_VNUM '$1 !~ /^#/ && NF >= 3 { printf "INSERT INTO shop_item (shop_vnum, item_vnum, count) VALUES (%d, %d, %d);\n", shop, $1, $2 }' "$ITEMS"
} | mysql -uroot player
echo "$VILLAGES" | while read -r map x y dir; do
npc="$MAPS/$map/npc.txt"
if awk -F'\t' -v v=$NPC_VNUM '$11 == v { found = 1 } END { exit !found }' "$npc"; then
echo "$map: NPC $NPC_VNUM already placed"
else
[ -z "$(tail -c 1 "$npc")" ] || echo >> "$npc"
printf 'm\t%d\t%d\t0\t0\t0\t%d\t1m\t100\t1\t%d\n' "$x" "$y" "$dir" "$NPC_VNUM" >> "$npc"
echo "$map: NPC $NPC_VNUM at $x,$y"
fi
done
mysql -uroot player -N -e "SELECT COUNT(*) FROM shop_item WHERE shop_vnum = $SHOP_VNUM"
echo "done; restart db and game (README.md)"