summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog-Trunk.txt4
-rw-r--r--conf/Changelog.txt3
-rw-r--r--conf/battle/feature.conf24
-rw-r--r--conf/log_athena.conf1
-rw-r--r--db/Changelog.txt6
-rw-r--r--db/item_buyingstore.txt1013
-rw-r--r--db/item_db.txt4
-rw-r--r--db/packet_db.txt28
-rw-r--r--db/skill_db.txt3
-rw-r--r--db/skill_require_db.txt2
-rw-r--r--db/skill_tree.txt11
-rw-r--r--doc/script_commands.txt17
-rw-r--r--sql-files/logs.sql8
-rw-r--r--sql-files/upgrade_svn14713_log.sql4
-rw-r--r--src/common/mmo.h2
-rw-r--r--src/map/Makefile.in6
-rw-r--r--src/map/atcommand.c4
-rw-r--r--src/map/battle.c1
-rw-r--r--src/map/battle.h1
-rw-r--r--src/map/buyingstore.c359
-rw-r--r--src/map/buyingstore.h29
-rw-r--r--src/map/chat.c7
-rw-r--r--src/map/clif.c323
-rw-r--r--src/map/clif.h14
-rw-r--r--src/map/itemdb.c28
-rw-r--r--src/map/itemdb.h1
-rw-r--r--src/map/log.h7
-rw-r--r--src/map/mail.c2
-rw-r--r--src/map/pc.h15
-rw-r--r--src/map/script.c18
-rw-r--r--src/map/skill.c6
-rw-r--r--src/map/trade.c4
-rw-r--r--src/map/unit.c2
-rw-r--r--vcproj-10/map-server_sql.vcxproj2
-rw-r--r--vcproj-10/map-server_txt.vcxproj2
-rw-r--r--vcproj-6/map-server_sql.dsp8
-rw-r--r--vcproj-6/map-server_txt.dsp8
-rw-r--r--vcproj-7.1/map-server_sql.vcproj6
-rw-r--r--vcproj-7.1/map-server_txt.vcproj6
-rw-r--r--vcproj-8/map-server_sql.vcproj7
-rw-r--r--vcproj-8/map-server_txt.vcproj8
-rw-r--r--vcproj-9/map-server_sql.vcproj8
-rw-r--r--vcproj-9/map-server_txt.vcproj8
43 files changed, 1978 insertions, 42 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt
index b5c9eff4d..8d361025d 100644
--- a/Changelog-Trunk.txt
+++ b/Changelog-Trunk.txt
@@ -1,5 +1,9 @@
Date Added
+2011/02/19
+ * Implemented buying store system (aka. reverse vending, purchase shop) together with related skill and items, without NPCs. [Ai4rei]
+ - For SQL apply upgrade_svn14713_log.sql to upgrade tables `picklog` and `zenylog`; for TXT no action is necessary.
+ - Requires 2010-04-20aRagexeRE or later and can be disabled in 'conf/battle/feature.conf'.
2011/02/17
* Merged enumeration update from renewal [14699/branches/renewal] for a future commit. [Ai4rei]
2011/02/16
diff --git a/conf/Changelog.txt b/conf/Changelog.txt
index 78b261c0f..e7af03e4e 100644
--- a/conf/Changelog.txt
+++ b/conf/Changelog.txt
@@ -1,5 +1,8 @@
Date Added
+2011/02/19
+ * Rev. 14713 Added map-server feature settings file 'battle/feature.conf'. [Ai4rei]
+ - Added setting 'feature.buying_store' to enable/disable the buying store system.
2011/02/15
* Rev. 14707 Added map-server battle setting 'gm_check_minlevel'. [Ai4rei]
2011/02/06
diff --git a/conf/battle/feature.conf b/conf/battle/feature.conf
new file mode 100644
index 000000000..934739c0f
--- /dev/null
+++ b/conf/battle/feature.conf
@@ -0,0 +1,24 @@
+// ______ __ __
+// /\ _ \/\ \__/\ \
+// __\ \ \L\ \ \ ,_\ \ \___ __ ___ __
+// /'__`\ \ __ \ \ \/\ \ _ `\ /'__`\/' _ `\ /'__`\
+///\ __/\ \ \/\ \ \ \_\ \ \ \ \/\ __//\ \/\ \/\ \L\.\_
+//\ \____\\ \_\ \_\ \__\\ \_\ \_\ \____\ \_\ \_\ \__/.\_\
+// \/____/ \/_/\/_/\/__/ \/_/\/_/\/____/\/_/\/_/\/__/\/_/
+// _ _ _ _ _ _ _ _ _ _ _ _ _
+// / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \
+//( e | n | g | l | i | s | h ) ( A | t | h | e | n | a )
+// \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
+//
+//--------------------------------------------------------------
+// eAthena Feature Configuration File
+//--------------------------------------------------------------
+// Note 1: Value is a config switch (on/off, yes/no or 1/0)
+// Note 2: Value is in percents (100 means 100%)
+// Note 3: Value is a bit field. If no description is given,
+// assume unit types (1: Pc, 2: Mob, 4: Pet, 8: Homun)
+//--------------------------------------------------------------
+
+// Buying store (Note 1)
+// Requires: 2010-04-20aRagexeRE or later
+feature.buying_store: on
diff --git a/conf/log_athena.conf b/conf/log_athena.conf
index 2f8effd18..0d5378a8f 100644
--- a/conf/log_athena.conf
+++ b/conf/log_athena.conf
@@ -16,6 +16,7 @@
// 2048 - (R) Log items placed/retrieved from storage.
// 4096 - (G) Log items placed/retrieved from guild storage.
// 8192 - (E) Log mail system transactions.
+// 16384 - (B) Log buying store transactions
// Example: Log trades+vending+script items+created items: 2+4+64+1024 = 1094
enable_logs: 1
diff --git a/db/Changelog.txt b/db/Changelog.txt
index add99e90d..3f164b3ce 100644
--- a/db/Changelog.txt
+++ b/db/Changelog.txt
@@ -9,6 +9,12 @@
13005 Angelic Wing Dagger: NEED INFO.
=======================
+2011/02/19
+ * Rev. 14713 Database updates required by buying store system implementation. [Ai4rei]
+ - Added database of items, that can be sold to a buying store (item_buyingstore.txt).
+ - Added items Buy_Stall_Permit (6377) and Shabby_Purchase_Street_Stall_License (12548).
+ - Updated packet database with buying store related packets.
+ - Added skill 'Open Buying Store' (ALL_BUYING_STORE).
2011/02/06
* Rev. 14697 Added the missing restricted skills to zone 6 for Endless Tower. (bugreport:4707) [L0ne_W0lf]
* Adjusted the rates for item using bAddEffOnSkill bonus.
diff --git a/db/item_buyingstore.txt b/db/item_buyingstore.txt
new file mode 100644
index 000000000..ec336c2a1
--- /dev/null
+++ b/db/item_buyingstore.txt
@@ -0,0 +1,1013 @@
+// Buying Store Item List
+// List of items, that can be sold to buying stores.
+// Format: <item id>
+// Example:
+// 512 // Apple
+// Note:
+// Items are in same order as data\buyingstoreitemlist.txt, which
+// must be edited as well for the client to accept added items.
+
+// items from 2010-03-12 update
+601 // Wing_Of_Fly
+602 // Wing_Of_Butterfly
+603 // Old_Blue_Box
+604 // Branch_Of_Dead_Tree
+605 // Anodyne
+606 // Aloebera
+607 // Yggdrasilberry
+608 // Seed_Of_Yggdrasil
+609 // Amulet
+610 // Leaf_Of_Yggdrasil
+611 // Spectacles
+612 // Portable_Furnace
+613 // Iron_Hammer
+614 // Golden_Hammer
+615 // Oridecon_Hammer
+616 // Old_Card_Album
+617 // Old_Violet_Box
+618 // Worn_Out_Scroll
+619 // Unripe_Apple
+620 // Orange_Juice
+621 // Bitter_Herb
+622 // Rainbow_Carrot
+623 // Earthworm_The_Dude
+624 // Rotten_Fish
+625 // Lusty_Iron
+626 // Monster_Juice
+627 // Sweet_Milk
+628 // Well_Dried_Bone
+629 // Singing_Flower
+630 // Dew_Laden_Moss
+631 // Deadly_Noxious_Herb
+632 // Fatty_Chubby_Earthworm
+633 // Baked_Yam
+634 // Tropical_Banana
+635 // Horror_Of_Tribe
+636 // No_Recipient
+637 // Old_Broom
+638 // Silver_Knife_Of_Chaste
+639 // Armlet_Of_Obedience
+640 // Shining_Stone
+641 // Contracts_In_Shadow
+642 // Book_Of_Devil
+643 // Pet_Incubator
+644 // Gift_Box
+645 // Center_Potion
+656 // Awakening_Potion
+657 // Berserk_Potion
+658 // Union_Of_Tribe
+659 // Heart_Of_Her
+660 // Prohibition_Red_Candle
+661 // Sway_Apron
+662 // Inspector_Certificate
+663 // Korea_Rice_Cake
+664 // Gift_Box_1
+665 // Gift_Box_2
+666 // Gift_Box_3
+667 // Gift_Box_4
+668 // Handsei
+669 // Rice_Cake_Soup
+678 // Poison_Bottle
+679 // Gold_Pill
+681 // Memory_Of_Wedding
+682 // Realgar_Wine
+683 // Exorcize_Herb
+684 // Durian
+686 // Earth_Scroll_1_3
+687 // Earth_Scroll_1_5
+688 // Cold_Scroll_1_3
+689 // Cold_Scroll_1_5
+690 // Fire_Scroll_1_3
+691 // Fire_Scroll_1_5
+692 // Wind_Scroll_1_3
+693 // Wind_Scroll_1_5
+694 // Ghost_Scroll_1_3
+695 // Ghost_Scroll_1_5
+696 // Fire_Scroll_2_1
+697 // Fire_Scroll_2_5
+698 // Fire_Scroll_3_1
+699 // Fire_Scroll_3_5
+700 // Cold_Scroll_2_1
+12000 // Cold_Scroll_2_5
+12001 // Holy_Scroll_1_3
+12002 // Holy_Scroll_1_5
+12003 // Holy_Scroll_2_1
+12004 // Arrow_Container
+12005 // Iron_Arrow_Container
+12006 // Steel_Arrow_Container
+12007 // Ori_Arrow_Container
+12008 // Fire_Arrow_Container
+12009 // Silver_Arrow_Container
+12010 // Wind_Arrow_Container
+12011 // Stone_Arrow_Container
+12012 // Crystal_Arrow_Container
+12013 // Shadow_Arrow_Container
+12014 // Imma_Arrow_Container
+12015 // Rusty_Arrow_Container
+12016 // Speed_Up_Potion
+12017 // Slow_Down_Potion
+12018 // Fire_Cracker
+12020 // Water_Of_Darkness
+12027 // Giggling_Box
+12028 // Box_Of_Thunder
+12029 // Gloomy_Box
+12030 // Box_Of_Grudge
+12031 // Sleepy_Box
+12032 // Box_Of_Storm
+12033 // Box_Of_Sunlight
+12034 // Painting_Box
+12040 // Stone_Of_Intelligence_
+12041 // Str_Dish01
+12042 // Str_Dish02
+12043 // Str_Dish03
+12044 // Str_Dish04
+12045 // Str_Dish05
+12046 // Int_Dish01
+12047 // Int_Dish02
+12048 // Int_Dish03
+12049 // Int_Dish04
+12050 // Int_Dish05
+12051 // Vit_Dish01
+12052 // Vit_Dish02
+12053 // Vit_Dish03
+12054 // Vit_Dish04
+12055 // Vit_Dish05
+12056 // Agi_Dish01
+12057 // Agi_Dish02
+12058 // Agi_Dish03
+12059 // Agi_Dish04
+12060 // Agi_Dish05
+12061 // Dex_Dish01
+12062 // Dex_Dish02
+12063 // Dex_Dish03
+12064 // Dex_Dish04
+12065 // Dex_Dish05
+12066 // Luk_Dish01
+12067 // Luk_Dish02
+12068 // Luk_Dish03
+12069 // Luk_Dish04
+12070 // Luk_Dish05
+12071 // Str_Dish06
+12072 // Str_Dish07
+12073 // Str_Dish08
+12074 // Str_Dish09
+12075 // Str_Dish10
+12076 // Int_Dish06
+12077 // Int_Dish07
+12078 // Int_Dish08
+12079 // Int_Dish09
+12080 // Int_Dish10
+12081 // Vit_Dish06
+12082 // Vit_Dish07
+12083 // Vit_Dish08
+12084 // Vit_Dish09
+12085 // Vit_Dish10
+12086 // Agi_Dish06
+12087 // Agi_Dish07
+12088 // Agi_Dish08
+12089 // Agi_Dish09
+12090 // Agi_Dish10
+12091 // Dex_Dish06
+12092 // Dex_Dish07
+12093 // Dex_Dish08
+12094 // Dex_Dish09
+12095 // Dex_Dish10
+12096 // Luk_Dish06
+12097 // Luk_Dish07
+12098 // Luk_Dish08
+12099 // Luk_Dish09
+12100 // Luk_Dish10
+12101 // Citron
+12102 // Meat_Skewer
+12103 // Bloody_Dead_Branch
+12104 // Random_Quiver
+12105 // Set_Of_Taiming_Item
+12106 // Accessory_Box
+12107 // Wrapped_Mask
+12108 // Bundle_Of_Magic_Scroll
+12109 // Poring_Box
+12110 // First_Aid_Kit
+12111 // Food_Package
+12112 // Tropical_Sograt
+12113 // Vermilion_The_Beach
+12114 // Elemental_Fire
+12115 // Elemental_Water
+12116 // Elemental_Earth
+12117 // Elemental_Wind
+12118 // Resist_Fire
+12119 // Resist_Water
+12120 // Resist_Earth
+12121 // Resist_Wind
+12122 // Sesame_Pastry
+12123 // Honey_Pastry
+12124 // Rainbow_Cake
+12125 // Outdoor_Cooking_Kits
+12126 // Indoor_Cooking_Kits
+12127 // High_end_Cooking_Kits
+12128 // Imperial_Cooking_Kits
+12129 // Fantastic_Cooking_Kits
+12130 // Cookie_Bag
+12132 // Red_Bag
+12144 // Sphere_Case_Wind
+12145 // Sphere_Case_Darkness
+12146 // Sphere_Case_Poison
+12147 // Sphere_Case_Water
+12148 // Sphere_Case_Fire
+12149 // Bullet_Case
+12150 // Bullet_Case_Blood
+12151 // Bullet_Case_Silver
+12183 // Holy_Arrow_Quiver
+12184 // Mercenary_Red_Potion
+12185 // Mercenary_Blue_Potion
+12194 // Hometown_Gift
+12195 // Plain_Rice_Cake
+12196 // Hearty_Rice_Cake
+12197 // Salty_Rice_Cake
+12198 // Lucky_Rice_Cake
+12241 // M_Center_Potion
+12242 // M_Awakening_Potion
+12243 // M_Berserk_Potion
+12246 // Magic_Card_Album
+12260 // Cool_Summer_Outfit
+12290 // Mysterious_Can
+12291 // Mysterious_PET_Bottle
+12292 // Unripe_Fruit
+12293 // Dried_Yggdrasilberry
+12341 // Special_Alloy_Trap_Box
+12346 // Unripe_Acorn
+12347 // Acorn_Jelly
+12353 // Tiny_Waterbottle
+12358 // Fan_Of_Wind
+12359 // Very_Soft_Plant
+12360 // Very_Red_Juice
+12362 // Kuloren
+12364 // Staff_Of_Leader
+12365 // Charming_Lotus
+12366 // Gril_Doll
+12367 // Luxury_Whisky_Bottle
+12368 // Splendid_Mirror
+12369 // Coconut
+12371 // Magical_Lithography
+12372 // Hell_Contract
+12373 // Boy's_Naivety
+12374 // Flaming_Ice
+12376 // Mysterious_Can2
+12377 // Mysterious_PET_Bottle2
+12379 // Pope's_Cookie
+12383 // Vulcan_Bullet_Magazine
+12392 // RepairA
+12393 // RepairB
+12394 // RepairC
+12395 // Tantanmen
+//12414
+12717 // Poison_Paralysis
+12718 // Poison_Leech
+12719 // Poison_Oblivion
+12720 // Poison_Contamination
+12721 // Poison_Numb
+12722 // Poison_Fever
+12723 // Poison_Laughing
+12724 // Poison_Fatigue
+12734 // Runstone_Quality
+12735 // Runstone_Ancient
+12736 // Runstone_Mystic
+12737 // Runstone_Ordinary
+12738 // Runstone_Rare
+506 // Green_Potion
+507 // Red_Herb
+508 // Yellow_Herb
+509 // White_Herb
+510 // Blue_Herb
+511 // Green_Herb
+512 // Apple
+513 // Banana
+514 // Grape
+515 // Carrot
+516 // Sweet_Potato
+517 // Meat
+518 // Honey
+519 // Milk
+520 // Leaflet_Of_Hinal
+521 // Leaflet_Of_Aloe
+522 // Fruit_Of_Mastela
+523 // Holy_Water
+525 // Panacea
+526 // Royal_Jelly
+528 // Monster's_Feed
+529 // Candy
+530 // Candy_Striper
+531 // Apple_Juice
+532 // Banana_Juice
+533 // Grape_Juice
+534 // Carrot_Juice
+535 // Pumpkin
+536 // Ice_Cream
+537 // Pet_Food
+538 // Well_Baked_Cookie
+539 // Piece_Of_Cake
+544 // Fish_Slice
+548 // Cheese
+549 // Nice_Sweet_Potato
+550 // Popped_Rice
+551 // Shusi
+553 // Bun
+564 // Rice_Ball
+566 // Tomyumkung
+567 // Prawn
+568 // Lemon
+569 // Novice_Potion
+570 // Lucky_Candy
+571 // Lucky_Candy_Cane
+572 // Lucky_Cookie
+574 // Egg
+576 // Prickly_Fruit
+577 // Grain
+578 // Strawberry
+579 // Delicious_Fish
+580 // Bread
+581 // Mushroom
+582 // Orange
+584 // Fish_Ball_Soup
+587 // Prickly_Fruit_
+591 // Caviar_Pancake
+592 // Jam_Pancake
+593 // Honey_Pancake
+594 // Sour_Cream_Pancake
+595 // Mushroom_Pancake
+//11513
+11515 // Coconut
+11516 // Acai_Fruit
+//11517
+701 // Ora_Ora
+702 // Animal_Blood
+703 // Hinalle
+704 // Aloe
+705 // Clover
+706 // Four_Leaf_Clover
+707 // Singing_Plant
+708 // Ment
+709 // Izidor
+710 // Illusion_Flower
+711 // Shoot
+712 // Flower
+713 // Empty_Bottle
+715 // Yellow_Gemstone
+716 // Red_Gemstone
+717 // Blue_Gemstone
+718 // Dark_Red_Jewel
+719 // Violet_Jewel
+720 // Skyblue_Jewel
+721 // Azure_Jewel
+722 // Scarlet_Jewel
+723 // Cardinal_Jewel
+724 // Cardinal_Jewel_
+725 // Red_Jewel
+726 // Blue_Jewel
+727 // White_Jewel
+728 // Golden_Jewel
+729 // Bluish_Green_Jewel
+730 // Crystal_Jewel
+731 // Crystal_Jewel_
+732 // Crystal_Jewel__
+733 // Crystal_Jewel___
+734 // Red_Frame
+735 // Blue_Porcelain
+736 // White_Platter
+737 // Black_Ladle
+738 // Pencil_Case
+739 // Rouge
+740 // Stuffed_Doll
+741 // Poring_Doll
+742 // Chonchon_Doll
+743 // Spore_Doll
+744 // Bunch_Of_Flowers
+745 // Wedding_Bouquet
+746 // Glass_Bead
+747 // Crystal_Mirror
+748 // Witherless_Rose
+749 // Frozen_Rose
+750 // Baphomet_Doll
+751 // Osiris_Doll
+752 // Grasshopper_Doll
+753 // Monkey_Doll
+754 // Raccoondog_Doll
+756 // Oridecon_Stone
+757 // Elunium_Stone
+901 // Danggie
+902 // Tree_Root
+903 // Reptile_Tongue
+904 // Scorpion's_Tail
+905 // Stem
+906 // Pointed_Scale
+907 // Resin
+908 // Spawn
+909 // Jellopy
+910 // Garlet
+911 // Scell
+912 // Zargon
+913 // Tooth_Of_Bat
+914 // Fluff
+915 // Chrysalis
+916 // Feather_Of_Birds
+917 // Talon
+918 // Sticky_Webfoot
+919 // Animal's_Skin
+920 // Claw_Of_Wolves
+921 // Mushroom_Spore
+922 // Orcish_Cuspid
+923 // Evil_Horn
+924 // Powder_Of_Butterfly
+925 // Bill_Of_Birds
+926 // Scale_Of_Snakes
+928 // Insect_Feeler
+929 // Immortal_Heart
+930 // Rotten_Bandage
+931 // Orcish_Voucher
+932 // Skel_Bone
+934 // Mementos
+935 // Shell
+936 // Scales_Shell
+937 // Posionous_Canine
+938 // Sticky_Mucus
+939 // Bee_Sting
+940 // Grasshopper's_Leg
+941 // Nose_Ring
+942 // Yoyo_Tail
+943 // Solid_Shell
+944 // Horseshoe
+945 // Raccoon_Leaf
+946 // Snail's_Shell
+947 // Horn
+948 // Bear's_Foot
+949 // Feather
+950 // Heart_Of_Mermaid
+951 // Fin
+952 // Cactus_Needle
+953 // Stone_Heart
+954 // Shining_Scales
+955 // Worm_Peelings
+956 // Gill
+957 // Decayed_Nail
+958 // Horrendous_Mouth
+959 // Rotten_Scale
+960 // Nipper
+961 // Conch
+962 // Tentacle
+963 // Sharp_Scale
+964 // Crap_Shell
+965 // Clam_Shell
+966 // Flesh_Of_Clam
+967 // Turtle_Shell
+968 // Voucher_Of_Orcish_Hero
+969 // Gold
+971 // Detrimindexta
+972 // Karvodailnirol
+973 // Counteragent
+974 // Mixture
+975 // Scarlet_Dyestuffs
+976 // Lemon_Dyestuffs
+978 // Cobaltblue_Dyestuffs
+979 // Darkgreen_Dyestuffs
+980 // Orange_Dyestuffs
+981 // Violet_Dyestuffs
+982 // White_Dyestuffs
+983 // Black_Dyestuffs
+984 // Oridecon
+985 // Elunium
+986 // Anvil
+987 // Oridecon_Anvil
+988 // Golden_Anvil
+989 // Emperium_Anvil
+990 // Boody_Red
+991 // Crystal_Blue
+992 // Wind_Of_Verdure
+993 // Yellow_Live
+994 // Flame_Heart
+995 // Mistic_Frozen
+996 // Rough_Wind
+997 // Great_Nature
+998 // Iron
+999 // Steel
+1000 // Star_Crumb
+1001 // Sparkling_Dust
+1002 // Iron_Ore
+1003 // Coal
+1004 // Patriotism_Marks
+1005 // Hammer_Of_Blacksmith
+1006 // Old_Magic_Book
+1007 // Penetration
+1008 // Frozen_Heart
+1009 // Sacred_Marks
+1010 // Phracon
+1011 // Emveretarcon
+1012 // Lizard_Scruff
+1013 // Colorful_Shell
+1014 // Jaws_Of_Ant
+1015 // Thin_N'_Long_Tongue
+1016 // Rat_Tail
+1017 // Moustache_Of_Mole
+1018 // Nail_Of_Mole
+1019 // Wooden_Block
+1020 // Long_Hair
+1021 // Dokkaebi_Horn
+1022 // Fox_Tail
+1023 // Fish_Tail
+1024 // Chinese_Ink
+1025 // Spiderweb
+1026 // Acorn
+1027 // Porcupine_Spike
+1028 // Wild_Boar's_Mane
+1029 // Tiger's_Skin
+1030 // Tiger_Footskin
+1031 // Limb_Of_Mantis
+1032 // Blossom_Of_Maneater
+1033 // Root_Of_Maneater
+1034 // Cobold_Hair
+1035 // Dragon_Canine
+1036 // Dragon_Scale
+1037 // Dragon_Train
+1038 // Petite_DiablOfs_Horn
+1039 // Petite_DiablOfs_Wing
+1040 // Elder_Pixie's_Beard
+1041 // Lantern
+1042 // Short_Leg
+1043 // Nail_Of_Orc
+1044 // Tooth_Of_
+1045 // Sacred_Masque
+1046 // Tweezer
+1047 // Head_Of_Medusa
+1048 // Slender_Snake
+1049 // Skirt_Of_Virgin
+1050 // Tendon
+1051 // Detonator
+1052 // Single_Cell
+1053 // Tooth_Of_Ancient_Fish
+1054 // Lip_Of_Ancient_Fish
+1055 // Earthworm_Peeling
+1056 // Grit
+1057 // Moth_Dust
+1058 // Wing_Of_Moth
+1059 // Transparent_Cloth
+1060 // Golden_Hair
+1061 // Starsand_Of_Witch
+1062 // Pumpkin_Head
+1063 // Sharpened_Cuspid
+1064 // Reins
+1065 // Booby_Trap
+1066 // Tree_Of_Archer_1
+1067 // Tree_Of_Archer_2
+1068 // Tree_Of_Archer_3
+1088 // Morocc_Potion
+1089 // Payon_Potion
+1092 // Empty_Cylinder
+1093 // Empty_Potion
+1094 // Short_Daenggie
+1095 // Needle_Of_Alarm
+1096 // Round_Shell
+1097 // Worn_Out_Page
+1098 // Manacles
+1099 // Worn_Out_Prison_Uniform
+6001 // Essence_Of_Fire
+6002 // Token_Of_Apostle
+6003 // Soul_Pendant
+6004 // Bapho_Doll
+6008 // Wood
+6010 // Pickaxe
+6020 // Fur
+6021 // Peaked_Hat
+6022 // Hard_Skin
+6023 // Mystic_Horn
+6032 // Horn_Of_Hilsrion
+6033 // Horn_Of_Tendrilion
+6073 // Dragon's_Mane
+6075 // Crystalized_Teardrop
+6086 // Withered_Flower
+6087 // Crystal_Of_Soul_01
+6088 // Crystal_Of_Soul_02
+6089 // Piece_Of_Darkness
+6090 // Purified_Bradium
+6091 // Dark_Red_Scale
+6095 // Flavored_Alcohol
+6096 // Fish_With_Blue_Back
+6097 // Pumpkin_Pie_
+6098 // Small_Snow_Flower
+6099 // Grilled_Rice_Cake
+6100 // Damp_Darkness
+6104 // Big_Cell
+6105 // Morning_Dew
+6106 // Well_Ripened_Berry
+6107 // Sunset_On_The_Rock
+6108 // Apple_Pudding
+6109 // Plant_Neutrient
+6110 // Vital_Flower
+6111 // Mystic_Stone
+6112 // Fresh_Plant
+6113 // Vital_Flower_
+6114 // Flame_Gemstone
+6115 // Bun_
+6120 // Face_Paint
+6123 // Surface_Paint
+6128 // Guillotine_Antidote
+6144 // Heartbroken_Tears
+6145 // Vulcan_Bullet
+6146 // Magic_Gear_Fuel
+6147 // Liquid_Condensed_Bullet
+6186 // Monkey_Wrench
+//6189
+//6190
+//6191
+//6192
+//6193
+//6194
+//6195
+//6196
+//6197
+//6198
+//6199
+//6200
+//6201
+//6202
+//6203
+//6204
+//6205
+//6210 // Seed_Of_Thorny_Plant
+//6211 // Bloodsuck_Plant_Seed
+//6212 // Bomb_Mushroom_Spore
+//6213 // Explosive_Powder
+//6214 // Smokes_Powder
+//6215 // Tear_Gas
+//6216 // Oil_Bottle
+//6217 // Mandragora_Flowerpot
+6223 // Carnium
+6224 // Bradium
+//6244 // Dark_Powder
+//6245 // Black_Powder
+//6246 // Yellow_Powder
+//6247 // White_Powder
+//6248 // Chowder_Pot
+//6249 // Savage_Meat
+//6250 // Iron_Cooking_Skewer
+//6251 // Black_Charcoal
+//6252 // Wolf's_Blood
+//6253 // Cold_Ice
+//6254 // Seasoned_Tough_Meat
+//6255 // Large_Pan
+//6256 // Powdered_Ice
+//6257 // Ice_Crystal
+//6258 // Comodo_Tropical_Fruit
+//6259 // Drosera_Feeler
+//6260 // Petite_Tail
+//6261 // Fine_Noodles
+//6262 // Cold_Broth
+//6263 // Coconut
+//6264 // Melon
+//6265 // Pineapple
+//6279 // Apple_Bomb_Guidebook
+//6280 // Pineapple_Bomb_Guidebook
+//6281 // Coconut_Bomb_Guidebook
+//6282 // Melon_Bomb_Guidebook
+//6283 // Banana_Bomb_Guidebook
+//6284 // Plant_Genetic_Cultivation_Guide
+//6285 // Improved_Potion_Creation_Manual
+6297 // Empty_Potion_Bottle
+//6321 // Rake_Helmet
+//6322 // Antler_Helmet
+//6323 // Two-Horn_Helmet
+//6324 // One-Horn_Helmet
+//6325 // White_Spider_Legs
+//6326 // Queen_Scraba_Shell
+//6360 // Scarlet_Point
+//6361 // Indigo_Point
+//6362 // Yellow_Wish_Point
+//6363 // Lime_Green_Point
+7001 // Mould_Powder
+7002 // Ogre_Tooth
+7003 // Anolian_Skin
+7004 // Mud_Lump
+7005 // Skull
+7006 // Wing_Of_Red_Bat
+7007 // Claw_Of_Rat
+7008 // Stiff_Horn
+7009 // Glitter_Shell
+7010 // Tail_Of_Steel_Scorpion
+7011 // Claw_Of_Monkey
+7012 // Tough_Scalelike_Stem
+7013 // Coral_Reef
+7014 // Old_Portrait
+7015 // Bookclip_In_Memory
+7016 // Spoon_Stub
+7017 // Executioner's_Mitten
+7018 // Young_Twig
+7019 // Loki's_Whispers
+7020 // Mother's_Nightmare
+7021 // Foolishness_Of_Blind
+7022 // Old_Hilt
+7023 // Blade_Lost_In_Darkness
+7024 // Bloody_Edge
+7026 // Key_Of_Clock_Tower
+7027 // Underground_Key
+7030 // Claw_Of_Desert_Wolf
+7031 // Old_Frying_Pan
+7032 // Piece_Of_Egg_Shell
+7033 // Poison_Spore
+7034 // Red_Socks_With_Holes
+7035 // Matchstick
+7036 // Fang_Of_Garm
+7038 // Yarn
+7041 // Fine_Grit
+7043 // Fine_Sand
+7047 // Alice's_Apron
+7048 // Talon_Of_Griffin
+7049 // Stone
+7053 // Cyfar
+7054 // Brigan
+7055 // Animal_Pooopoo
+7056 // Payroll_Of_Kafra
+7057 // Gallar_Horn
+7058 // Gullraifnir
+7063 // Soft_Feather
+7064 // Dragon_Fly_Wing
+7065 // Sea_Otter_Leather
+7066 // Ice_Piece
+7067 // Stone_Piece
+7068 // Burn_Tree
+7069 // Broken_Armor_Piece
+7070 // Broken_Shell
+7071 // Tatters_Clothes
+7072 // Rust_Suriken
+7073 // Jewel_Of_Prayer
+7074 // Iron_Glove
+7075 // Iron_Maiden
+7076 // Mystery_Wheel
+7077 // Silver_Fancy
+7078 // Anger_Of_Valkurye
+7079 // Feather_Of_Angel
+7080 // Foot_Step_Of_Cat
+7081 // Beard_Of_Women
+7082 // Root_Of_Stone
+7083 // Soul_Of_Fish
+7084 // Saliva_Of_Bird
+7085 // Tendon_Of_Bear
+7086 // Symbol_Of_Sun
+7087 // Breath_Of_Soul
+7088 // Crystal_Of_Snow
+7089 // Indication_Of_Tempest
+7090 // Slilince_Wave
+7091 // Rough_Billows
+7092 // Air_Stream
+7093 // Wheel
+7094 // Mystery_Piece
+7095 // Broken_Steel_Piece
+7096 // Cold_Magma
+7097 // Burning_Heart
+7098 // Live_Coal
+7099 // Old_Magic_Circle
+7100 // Sharp_Leaf
+7101 // Peco_Wing_Feather
+7102 // Hideous_Dream
+7103 // Unknown_Liquid_Bottle
+7104 // Fake_Angel_Wing
+7105 // Fake_Angel_Loop
+7106 // Goat's_Horn
+7107 // Gaoat's_Skin
+7108 // Boroken_Shiled_Piece
+7109 // Shine_Spear_Blade
+7110 // Vroken_Sword
+7111 // Smooth_Paper
+7112 // Fright_Paper_Blade
+7113 // Broken_Pharaoh_Symbol
+7114 // Tutankhamen's_Mask
+7115 // Harpy's_Feather
+7116 // Harpy's_Claw
+7117 // Rent_Spell_Book
+7118 // Rent_Scroll
+7119 // Spawns
+7120 // Burning_Horse_Shoe
+7121 // Honey_Jar
+7122 // Hot_Hair
+7123 // Dragon's_Skin
+7124 // Sand_Lump
+7125 // Scropion's_Nipper
+7126 // Large_Jellopy
+7127 // Alcol_Create_Book
+7128 // FireBottle_Create_Book
+7129 // Acid_Create_Book
+7130 // Plant_Create_Book
+7131 // Mine_Create_Book
+7132 // Coating_Create_Book
+7133 // Slim_Potion_Create_Book
+7134 // Medicine_Bowl
+7140 // Seed_Of_Life
+7141 // Yggdrasilberry_Dew
+7143 // Life_Force_Pot
+7144 // Normal_Potion_Book
+7147 // Jasmin
+7149 // Yellow_Plate
+7150 // Bamboo_Cut
+7151 // Oil_Paper
+7152 // Glossy_Hair
+7153 // Old_Japaness_Clothes
+7154 // Poison_Powder
+7155 // Poison_Toad's_Skin
+7156 // Broken_Shuriken
+7157 // Black_Mask
+7158 // Broken_Wine_Vessel
+7159 // Tengu's_Nose
+7160 // Lord's_Passable_Ticket
+7161 // Black_Bear's_Skin
+7162 // Cloud_Piece
+7163 // Sharp_Feeler
+7164 // Hard_Peach
+7165 // Limpid_Celestial_Robe
+7166 // Soft_Silk_Cloth
+7167 // Mystery_Iron_Bit
+7168 // Great_Wing
+7169 // Taegeuk_Plate
+7170 // Tuxedo
+7171 // Leopard_Skin
+7172 // Leopard_Talon
+7174 // Packing_Ribbon
+7175 // Packing_Paper
+7182 // Cacao
+7186 // Thin_Stem
+7187 // Festival_Mask
+7188 // Browny_Root
+7189 // Heart_Of_Tree
+7190 // Solid_Peeling
+7191 // Lamplight
+7192 // Blade_Of_Pinwheel
+7193 // Germinating_Sprout
+7194 // Soft_Leaf
+7195 // Air_Rifle
+7196 // Shoulder_Protection
+7197 // Tough_Vines
+7198 // Great_Leaf
+7199 // Coupon
+7200 // Flexible_String
+7201 // Log
+7202 // Beetle_Nipper
+7203 // Solid_Twig
+7204 // Gunpowder
+7205 // Piece_Of_Black_Cloth
+7206 // Black_Kitty_Doll
+7207 // Old_Manteau
+7208 // Rusty_Cleaver
+7209 // Dullahan's_Helm
+7210 // Dullahan_Armor
+7211 // Rojerta_Piece
+7212 // Hanging_Doll
+7213 // Needle_Pouch
+7214 // Bat_Cage
+7215 // Broken_Needle
+7216 // Red_Scarf
+7217 // Spool
+7218 // Rotten_Rope
+7219 // Striped_Socks
+7220 // Ectoplasm
+7221 // Tangled_Chain
+7222 // Tree_Knot
+7223 // Distorted_Portrait
+7225 // Pumpkin_Bucket
+7226 // Pill
+7262 // Fan
+7263 // Cat_Eyed_Stone
+7264 // Dried_Sand
+7265 // Dragon_Horn
+7266 // Dragon_Fang
+7267 // Tiger_Skin_Panties
+7268 // Little_Blacky_Ghost
+7269 // Bib
+7270 // Milk_Bottle
+7277 // Munak_Doll
+7286 // Chilli
+7289 // Olivine
+7290 // Phlogopite
+7291 // Agate
+7292 // Muscovite
+7293 // Rose_Quartz
+7294 // Turquoise
+7295 // Citrine
+7296 // Pyroxene
+7297 // Biotite
+7298 // Leaf_Clothes
+7299 // Bamboo_Basket
+7300 // Gemstone
+7301 // Sword_Accessory
+7303 // Bag_Of_Rice
+7312 // Jubilee
+7315 // Dark_Crystal_Fragment
+7316 // Long_Limb
+7317 // Screw
+7318 // Old_Pick
+7319 // Old_Steel_Plate
+7320 // Air_Pollutant
+7321 // Fragment_Of_Crystal
+7322 // Poisonous_Gas
+7323 // Battered_Kettle
+7325 // Tube
+7326 // Fluorescent_Liquid
+7327 // Headlamp
+7340 // Will_Of_Darkness
+7345 // Armlet_Of_Prisoner
+7352 // Transparent_Plate01
+7353 // Transparent_Plate02
+7354 // Transparent_Plate03
+7355 // Transparent_Plate04
+7356 // Piece_Of_Crest1
+7357 // Piece_Of_Crest2
+7358 // Piece_Of_Crest3
+7359 // Piece_Of_Crest4
+7419 // Embryo_HandBook
+7433 // Scroll
+7434 // Elemental_Potion_Book
+7435 // Golden_Bracelet
+7436 // Piece_Of_Memory_Green
+7437 // Piece_Of_Memory_Purple
+7438 // Piece_Of_Memory_Blue
+7439 // Piece_Of_Memory_Red
+7440 // Red_Feather
+7441 // Blue_Feather
+7442 // Cursed_Seal
+7443 // Tri_Headed_Dragon_Head
+7444 // Treasure_Box
+7445 // Dragonball_Green
+7446 // Dragonball_Blue
+7447 // Dragonball_Red
+7448 // Dragonball_Yellow
+7449 // Bloody_Page
+7450 // Piece_Of_Bone_Armor
+7451 // Scale_Of_Red_Dragon
+7452 // Yellow_Spice
+7453 // Sweet_Sauce
+7454 // Plain_Sauce
+7455 // Hot_Sauce
+7456 // Red_Spice
+7457 // Cooking_Oil
+7472 // Cookbook01
+7473 // Cookbook02
+7474 // Cookbook03
+7475 // Cookbook04
+7476 // Cookbook05
+7477 // Cookbook06
+7478 // Cookbook07
+7479 // Cookbook08
+7480 // Cookbook09
+7481 // Cookbook10
+7482 // Pot
+7507 // Sturdy_Iron_Piece
+7510 // Valhalla_Flower
+7511 // Rune_Of_Darkness
+7512 // Burnt_Parts
+7513 // Pocket_Watch
+7521 // Flame_Stone
+7522 // Ice_Stone
+7523 // Wind_Stone
+7524 // Shadow_Orb
+7561 // Ice_Heart
+7562 // Ice_Scale
+7563 // Bloody_Rune
+7564 // Rotten_Meat
+7565 // Sticky_Poison
+7566 // Will_Of_Darkness_
+7567 // Suspicious_Hat
+7568 // White_Mask
+7574 // Ice_Particle
+7751 // Old_White_Cloth
+7752 // Clattering_Skull
+7753 // Broken_Farming_Utensil
+7754 // Broken_Crown
+7830 // Goddess_Tear
+7831 // Valkyrie_Token
+7832 // Brynhild_Armor_Piece
+7833 // Hero_Remains
+7834 // Andvari_Ring
+7835 // Dusk_Glow
+7836 // Dawn_Essence
+7837 // Cold_Moonlight
+7838 // Hazy_Starlight
+7931 // Poison_Kit
+7932 // Poison_Herb_Nerium
+7933 // Poison_Herb_Rantana
+7934 // Poison_Herb_Makulata
+7935 // Poison_Herb_Seratum
+7936 // Poison_Herb_Scopolia
+7937 // Poison_Herb_Amoena
+7938 // Light_Granule
+7939 // Elder_Branch
+7940 // Special_Alloy_Trap
+11000 // Prontera_Book_01
+11001 // Adventure_Story01
+11002 // Great_Chef_Orleans01
+11003 // Legend_Of_Kafra01
+11004 // Mercenary_Rebellion
+11005 // Tyrant_Schmidt
+11006 // Blood_Flower01
+11007 // Blood_Flower02
+11008 // Barmund
+11009 // Adventure_Story02
+//11020
+//11021
+//11022 // Mix_Cooking_Ingredient_Book_1
+//11023 // Vitality_Boost_Research_Book
+//11024 // Energy_Drink_Formula
+
diff --git a/db/item_db.txt b/db/item_db.txt
index e97812060..48b8747e5 100644
--- a/db/item_db.txt
+++ b/db/item_db.txt
@@ -3293,7 +3293,7 @@
//6362,Yellow_Wish_Point,Yellow Wish Point,3,100,,5,,,,,,,,,,,,,{},{},{}
//6363,Lime_Green_Point,Lime Green Point,3,100,,5,,,,,,,,,,,,,{},{},{}
//6376,KVM_Badge
-//6377,Buy_Stall_Permit,Purchase Street Stall License,3,200,,10,,,,,,,,,,,,,{},{},{}
+6377,Buy_Stall_Permit,Purchase Street Stall License,3,200,,10,,,,,,,,,,,,,{},{},{}
//6378
//6379
//6380
@@ -4823,7 +4823,7 @@
//12471,LV5_Adrenaline_Scroll,
//12472,Convex_Mirror,
//12475,Cure_Free,
-//12548,Shabby_Purchase_Street_Stall_License,
+12548,Shabby_Purchase_Street_Stall_License,Shabby Purchase Street Stall License,2,500,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ buyingstore 2; },{},{}
//12553,Brysingamen_Piece_Box,
//12554,Asprika_Piece_Box,
//12555,Brynhild_Piece_Box,
diff --git a/db/packet_db.txt b/db/packet_db.txt
index 2bd70e641..26d4773ed 100644
--- a/db/packet_db.txt
+++ b/db/packet_db.txt
@@ -1488,8 +1488,8 @@ packet_ver: 25
0x080F,20
//2010-03-03aRagexeRE
-//0x0810,3
-//0x0811,-1
+0x0810,3
+0x0811,-1,reqopenbuyingstore,2:4:8:9:89
//0x0812,86
//0x0813,6
//0x0814,6
@@ -1499,11 +1499,11 @@ packet_ver: 25
//0x0819,4
//2010-03-09aRagexeRE
-//0x0813,-1
+0x0813,-1
//0x0814,2
//0x0815,6
-//0x0816,6
-//0x0818,-1
+0x0816,6
+0x0818,-1
//0x0819,10
//0x081A,4
//0x081B,4
@@ -1528,15 +1528,15 @@ packet_ver: 25
//0x081B,8
//2010-04-20aRagexeRE
-//0x0812,8
-//0x0814,86
-//0x0815,2
-//0x0817,6
-//0x0819,-1
-//0x081a,4
-//0x081b,10
-//0x081c,10
-//0x0824,6
+0x0812,8
+0x0814,86
+0x0815,2,reqclosebuyingstore,0
+0x0817,6,reqclickbuyingstore,2
+0x0819,-1,reqtradebuyingstore,2:4:8:12
+0x081a,4
+0x081b,10
+0x081c,10
+0x0824,6
//2010-06-01aRagexeRE
//0x0825,-1
diff --git a/db/skill_db.txt b/db/skill_db.txt
index b534986c8..2a39740df 100644
--- a/db/skill_db.txt
+++ b/db/skill_db.txt
@@ -938,6 +938,9 @@
// Episode 13.3
//2534,0,0,0,0,0,0,9,0,no,0,0,0,none,0 RETURN_TO_ELDICASTES,
+// Buying Store
+2535,0,0,4,0,0x1,0,1,0,no,0,0x1,0,none,0, ALL_BUYING_STORE,Open Buying Store
+
8001,9,6,4,0,0x1,0,5,1,no,0,0,0,magic,0, HLIF_HEAL,Healing Touch
8002,0,6,4,0,0x3,-1,5,1,no,0,0,0,none,0, HLIF_AVOID,Avoid
8003,0,0,0,0,0,1,5,0,no,0,0,0,none,0, HLIF_BRAIN,Brain Surgery
diff --git a/db/skill_require_db.txt b/db/skill_require_db.txt
index 6a81951ff..d9fa49e0e 100644
--- a/db/skill_require_db.txt
+++ b/db/skill_require_db.txt
@@ -454,6 +454,8 @@
1018,0,0,30,0,0,0,99,0,0,none,0,12114,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //SA_ELEMENTFIRE
1019,0,0,30,0,0,0,99,0,0,none,0,12117,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //SA_ELEMENTWIND
+2535,0,0,1,0,0,0,99,0,0,none,0,6377,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //ALL_BUYING_STORE#Open Buying Store
+
10010,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GD_BATTLEORDER##
10011,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GD_REGENERATION##
10012,0,0,1,0,0,0,99,0,0,none,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //GD_RESTORE##
diff --git a/db/skill_tree.txt b/db/skill_tree.txt
index d64f1fef7..27f616c11 100644
--- a/db/skill_tree.txt
+++ b/db/skill_tree.txt
@@ -86,6 +86,7 @@
5,155,1,0,0,0,0,0,0,0,0,0,0 //MC_LOUD#Crazy Uproar#
5,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby#
5,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R#
+5,2535,1,41,1,0,0,0,0,0,0,0,0 //ALL_BUYING_STORE#Open Buying Store#
//Thief
6,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill#
6,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid#
@@ -240,6 +241,7 @@
10,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby#
10,459,1,111,5,0,0,0,0,0,0,0,0 //BS_ADRENALINE2#Full Adrenaline Rush#
10,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R#
+10,2535,1,41,1,0,0,0,0,0,0,0,0 //ALL_BUYING_STORE#Open Buying Store#
//Hunter
11,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill#
11,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid#
@@ -511,6 +513,7 @@
18,497,1,228,10,0,0,0,0,0,0,0,0 //AM_TWILIGHT2#Twilight Alchemy 2#
18,498,1,228,10,0,0,0,0,0,0,0,0 //AM_TWILIGHT3#Twilight Alchemy 3#
18,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R#
+18,2535,1,41,1,0,0,0,0,0,0,0,0 //ALL_BUYING_STORE#Open Buying Store#
//Bard
19,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill#
19,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid#
@@ -668,6 +671,7 @@
23,53,1,52,3,0,0,0,0,0,0,0,0 //TF_DETOXIFY#Detoxify#
23,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby#
23,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R#
+23,2535,1,41,1,0,0,0,0,0,0,0,0 //ALL_BUYING_STORE#Open Buying Store#
//Gunslinger
24,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill#
24,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid#
@@ -810,6 +814,7 @@
4006,155,1,0,0,0,0,0,0,0,0,0,0 //MC_LOUD#Crazy Uproar#
4006,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby#
4006,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R#
+4006,2535,1,41,1,0,0,0,0,0,0,0,0 //ALL_BUYING_STORE#Open Buying Store#
//ThiefHigh
4007,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill#
4007,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid#
@@ -989,6 +994,7 @@
4011,410,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLBABY#Call Baby#
4011,459,1,111,5,0,0,0,0,0,0,0,0 //BS_ADRENALINE2#Full Adrenaline Rush#
4011,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R#
+4011,2535,1,41,1,0,0,0,0,0,0,0,0 //ALL_BUYING_STORE#Open Buying Store#
//Sniper
4012,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill#
4012,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid#
@@ -1303,6 +1309,7 @@
4019,497,1,228,10,0,0,0,0,0,0,0,0 //AM_TWILIGHT2#Twilight Alchemy 2#
4019,498,1,228,10,0,0,0,0,0,0,0,0 //AM_TWILIGHT3#Twilight Alchemy 3#
4019,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R#
+4019,2535,1,41,1,0,0,0,0,0,0,0,0 //ALL_BUYING_STORE#Open Buying Store#
//Clown
4020,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill#
4020,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid#
@@ -1508,6 +1515,7 @@
4028,408,1,0,0,0,0,0,0,0,0,0,0 //WE_BABY#Baby#
4028,409,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLPARENT#Call Parent#
4028,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R#
+4028,2535,1,41,1,0,0,0,0,0,0,0,0 //ALL_BUYING_STORE#Open Buying Store#
//Baby Thief
4029,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill#
4029,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid#
@@ -1666,6 +1674,7 @@
4033,1013,1,0,0,0,0,0,0,0,0,0,0 //BS_GREED#Greed#
4033,459,1,111,5,0,0,0,0,0,0,0,0 //BS_ADRENALINE2#Full Adrenaline Rush#
4033,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R#
+4033,2535,1,41,1,0,0,0,0,0,0,0,0 //ALL_BUYING_STORE#Open Buying Store#
//Baby Hunter
4034,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill#
4034,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid#
@@ -1945,6 +1954,7 @@
4041,497,1,228,10,0,0,0,0,0,0,0,0 //AM_TWILIGHT2#Twilight Alchemy 2#
4041,498,1,228,10,0,0,0,0,0,0,0,0 //AM_TWILIGHT3#Twilight Alchemy 3#
4041,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R#
+4041,2535,1,41,1,0,0,0,0,0,0,0,0 //ALL_BUYING_STORE#Open Buying Store#
//Baby Bard
4042,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill#
4042,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid#
@@ -2099,6 +2109,7 @@
4045,408,1,0,0,0,0,0,0,0,0,0,0 //WE_BABY#Baby#
4045,409,1,0,0,0,0,0,0,0,0,0,0 //WE_CALLPARENT#Call Parent#
4045,681,1,0,0,0,0,0,0,0,0,0,0 //ALL_INCCARRY#Enlarge Weight Limit R#
+4045,2535,1,41,1,0,0,0,0,0,0,0,0 //ALL_BUYING_STORE#Open Buying Store#
//Taekwon
4046,1,9,0,0,0,0,0,0,0,0,0,0 //NV_BASIC#Basic Skill#
4046,142,1,0,0,0,0,0,0,0,0,0,0 //NV_FIRSTAID#First Aid#
diff --git a/doc/script_commands.txt b/doc/script_commands.txt
index 0fa2a0200..8deea8d6c 100644
--- a/doc/script_commands.txt
+++ b/doc/script_commands.txt
@@ -4,7 +4,7 @@
//= A reference manual for the eAthena scripting language.
//= Commands are sorted depending on their functionality.
//===== Version ===========================================
-//= 3.35.20110106
+//= 3.36.20110219
//=========================================================
//= 1.0 - First release, filled will as much info as I could
//= remember or figure out, most likely there are errors,
@@ -155,6 +155,8 @@
//= Spellcheck. [Ai4rei]
//= 3.35.20110106
//= Removed bug warning from 'deletearray'. [Ai4rei]
+//= 3.36.20110219
+//= Added 'buyingstore' command. [Ai4rei]
//=========================================================
This document is a reference manual for all the scripting commands and functions
@@ -4424,6 +4426,19 @@ Example(s):
autoequip 1104,0;
---------------------------------------
+
+*buyingstore <slots>;
+
+Invokes buying store preparation window like the skill 'Open Buying Store',
+without the item requirement. Amount of slots is limited by the server to
+a maximum of 5 slots by default.
+
+Example:
+
+ // Gives the player oppurtunity to buy 4 different kinds of items.
+ buyingstore 4;
+
+---------------------------------------
//
4,1.- End of item-related commands
//
diff --git a/sql-files/logs.sql b/sql-files/logs.sql
index 177dee870..6a69e3e1f 100644
--- a/sql-files/logs.sql
+++ b/sql-files/logs.sql
@@ -1,7 +1,7 @@
#PickLog types (M)onsters Drop, (P)layers Drop/Take, Mobs Drop (L)oot Drop/Take,
# Players (T)rade Give/Take, Players (V)ending Sell/Take, (S)hop Sell/Take, (N)PC Give/Take,
# (C)onsumable Items, (A)dministrators Create/Delete, Sto(R)age, (G)uild Storage,
-# (E)mail attachment
+# (E)mail attachment,(B)uying Store
#Database: log
#Table: picklog
@@ -9,7 +9,7 @@ CREATE TABLE `picklog` (
`id` int(11) NOT NULL auto_increment,
`time` datetime NOT NULL default '0000-00-00 00:00:00',
`char_id` int(11) NOT NULL default '0',
- `type` enum('M','P','L','T','V','S','N','C','A','R','G','E') NOT NULL default 'P',
+ `type` enum('M','P','L','T','V','S','N','C','A','R','G','E','B') NOT NULL default 'P',
`nameid` int(11) NOT NULL default '0',
`amount` int(11) NOT NULL default '1',
`refine` tinyint(3) unsigned NOT NULL default '0',
@@ -22,7 +22,7 @@ CREATE TABLE `picklog` (
INDEX (`type`)
) ENGINE=MyISAM AUTO_INCREMENT=1 ;
-#ZenyLog types (M)onsters,(T)rade,(V)ending Sell/Buy,(S)hop Sell/Buy,(N)PC Change amount,(A)dministrators,(E)Mail
+#ZenyLog types (M)onsters,(T)rade,(V)ending Sell/Buy,(S)hop Sell/Buy,(N)PC Change amount,(A)dministrators,(E)Mail,(B)uying Store
#Database: log
#Table: zenylog
CREATE TABLE `zenylog` (
@@ -30,7 +30,7 @@ CREATE TABLE `zenylog` (
`time` datetime NOT NULL default '0000-00-00 00:00:00',
`char_id` int(11) NOT NULL default '0',
`src_id` int(11) NOT NULL default '0',
- `type` enum('M','T','V','S','N','A','E') NOT NULL default 'S',
+ `type` enum('M','T','V','S','N','A','E','B') NOT NULL default 'S',
`amount` int(11) NOT NULL default '0',
`map` varchar(11) NOT NULL default '',
PRIMARY KEY (`id`),
diff --git a/sql-files/upgrade_svn14713_log.sql b/sql-files/upgrade_svn14713_log.sql
new file mode 100644
index 000000000..be4059ebe
--- /dev/null
+++ b/sql-files/upgrade_svn14713_log.sql
@@ -0,0 +1,4 @@
+-- Adds 'B' to `type` in `picklog` and `zenylog`
+
+ALTER TABLE `picklog` MODIFY `type` ENUM('M','P','L','T','V','S','N','C','A','R','G','E','B') NOT NULL DEFAULT 'P';
+ALTER TABLE `zenylog` MODIFY `type` ENUM('M','T','V','S','N','A','E','B') NOT NULL DEFAULT 'S';
diff --git a/src/common/mmo.h b/src/common/mmo.h
index 181f972e5..fa41c99d8 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -84,7 +84,7 @@
#define MAX_ZENY 1000000000
#define MAX_FAME 1000000000
#define MAX_CART 100
-#define MAX_SKILL 1020
+#define MAX_SKILL 2536
#define GLOBAL_REG_NUM 256
#define ACCOUNT_REG_NUM 64
#define ACCOUNT_REG2_NUM 16
diff --git a/src/map/Makefile.in b/src/map/Makefile.in
index cf6a29d6c..cec75c69b 100644
--- a/src/map/Makefile.in
+++ b/src/map/Makefile.in
@@ -17,7 +17,8 @@ MAP_OBJ = map.o chrif.o clif.o pc.o status.o npc.o \
npc_chat.o chat.o path.o itemdb.o mob.o script.o \
storage.o skill.o atcommand.o battle.o battleground.o \
intif.o trade.o party.o vending.o guild.o pet.o \
- log.o mail.o date.o unit.o homunculus.o mercenary.o quest.o instance.o
+ log.o mail.o date.o unit.o homunculus.o mercenary.o quest.o instance.o \
+ buyingstore.o
MAP_TXT_OBJ = $(MAP_OBJ:%=obj_txt/%) \
obj_txt/mapreg_txt.o
MAP_SQL_OBJ = $(MAP_OBJ:%=obj_sql/%) \
@@ -26,7 +27,8 @@ MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \
chat.h itemdb.h mob.h script.h path.h \
storage.h skill.h atcommand.h battle.h battleground.h \
intif.h trade.h party.h vending.h guild.h pet.h \
- log.h mail.h date.h unit.h homunculus.h mercenary.h quest.h instance.h mapreg.h
+ log.h mail.h date.h unit.h homunculus.h mercenary.h quest.h instance.h mapreg.h \
+ buyingstore.h
HAVE_MYSQL=@HAVE_MYSQL@
ifeq ($(HAVE_MYSQL),yes)
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index 3035487da..6abee5223 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -1150,7 +1150,7 @@ ACMD_FUNC(storage)
{
nullpo_retr(-1, sd);
- if (sd->npc_id || sd->vender_id || sd->state.trading || sd->state.storage_flag)
+ if (sd->npc_id || sd->vender_id || sd->state.buyingstore || sd->state.trading || sd->state.storage_flag)
return -1;
if (storage_storageopen(sd) == 1)
@@ -1177,7 +1177,7 @@ ACMD_FUNC(guildstorage)
return -1;
}
- if (sd->npc_id || sd->vender_id || sd->state.trading)
+ if (sd->npc_id || sd->vender_id || sd->state.buyingstore || sd->state.trading)
return -1;
if (sd->state.storage_flag == 1) {
diff --git a/src/map/battle.c b/src/map/battle.c
index fd9bc90d6..aebb93d56 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -4007,6 +4007,7 @@ static const struct _battle_data {
{ "client_reshuffle_dice", &battle_config.client_reshuffle_dice, 0, 0, 1, },
{ "client_sort_storage", &battle_config.client_sort_storage, 0, 0, 1, },
{ "gm_check_minlevel", &battle_config.gm_check_minlevel, 60, 0, 100, },
+ { "feature_buying_store", &battle_config.feature_buying_store, 1, 0, 1, },
// BattleGround Settings
{ "bg_update_interval", &battle_config.bg_update_interval, 1000, 100, INT_MAX, },
{ "bg_short_attack_damage_rate", &battle_config.bg_short_damage_rate, 80, 0, INT_MAX, },
diff --git a/src/map/battle.h b/src/map/battle.h
index a3e35bcee..f11040c8a 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -481,6 +481,7 @@ extern struct Battle_Config
int client_reshuffle_dice; // Reshuffle /dice
int client_sort_storage;
int gm_check_minlevel; // min GM level for /check
+ int feature_buying_store;
// [BattleGround Settings]
int bg_update_interval;
diff --git a/src/map/buyingstore.c b/src/map/buyingstore.c
new file mode 100644
index 000000000..21629e641
--- /dev/null
+++ b/src/map/buyingstore.c
@@ -0,0 +1,359 @@
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#include "../common/cbasetypes.h"
+#include "../common/db.h" // ARR_FIND
+#include "../common/showmsg.h" // ShowWarning
+#include "../common/socket.h" // RBUF*
+#include "../common/strlib.h" // safestrncpy
+#include "atcommand.h" // msg_txt
+#include "battle.h" // battle_config.*
+#include "buyingstore.h" // struct s_buyingstore
+#include "clif.h" // clif_buyingstore_*
+#include "log.h" // log_pick_pc, log_zeny
+#include "pc.h" // struct map_session_data
+
+
+/// constants (client-side restrictions)
+#define BUYINGSTORE_MAX_PRICE 99990000
+#define BUYINGSTORE_MAX_AMOUNT 9999
+
+
+/// failure constants for clif functions
+enum e_buyingstore_failure
+{
+ BUYINGSTORE_CREATE = 1, // "Failed to open buying store."
+ BUYINGSTORE_CREATE_OVERWEIGHT = 2, // "Total amount of then possessed items exceeds the weight limit by %d. Please re-enter."
+ BUYINGSTORE_TRADE_BUYER_ZENY = 3, // "All items within the buy limit were purchased."
+ BUYINGSTORE_TRADE_BUYER_NO_ITEMS = 4, // "All items were purchased."
+ BUYINGSTORE_TRADE_SELLER_FAILED = 5, // "The deal has failed."
+ BUYINGSTORE_TRADE_SELLER_COUNT = 6, // "The trade failed, because the entered amount of item %s is higher, than the buyer is willing to buy."
+ BUYINGSTORE_TRADE_SELLER_ZENY = 7, // "The trade failed, because the buyer is lacking required balance."
+ BUYINGSTORE_CREATE_NO_INFO = 8, // "No sale (purchase) information available."
+};
+
+
+static unsigned int buyingstore_nextid = 0;
+
+
+/// Returns unique buying store id
+static unsigned int buyingstore_getuid(void)
+{
+ return buyingstore_nextid++;
+}
+
+
+bool buyingstore_setup(struct map_session_data* sd, unsigned char slots)
+{
+ if( !battle_config.feature_buying_store || sd->vender_id || sd->state.buyingstore || sd->state.trading || slots == 0 )
+ {
+ return false;
+ }
+
+ if( slots > MAX_BUYINGSTORE_SLOTS )
+ {
+ ShowWarning("buyingstore_setup: Requested %d slots, but server supports only %d slots.\n", (int)slots, MAX_BUYINGSTORE_SLOTS);
+ slots = MAX_BUYINGSTORE_SLOTS;
+ }
+
+ sd->buyingstore.slots = slots;
+ clif_buyingstore_open(sd);
+
+ return true;
+}
+
+
+void buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned char result, const char* storename, const uint8* itemlist, unsigned int count)
+{
+ unsigned int i, weight, listidx;
+ struct item_data* id;
+
+ if( !result || count == 0 )
+ {// canceled, or no items
+ return;
+ }
+
+ if( !battle_config.feature_buying_store || pc_istrading(sd) || sd->buyingstore.slots == 0 || count > sd->buyingstore.slots || zenylimit <= 0 || zenylimit > sd->status.zeny || !storename[0] )
+ {// disabled or invalid input
+ sd->buyingstore.slots = 0;
+ clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0);
+ return;
+ }
+
+ if( !pc_can_give_items(pc_isGM(sd)) )
+ {// custom: GM is not allowed to buy (give zeny)
+ sd->buyingstore.slots = 0;
+ clif_displaymessage(sd->fd, msg_txt(246));
+ clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0);
+ return;
+ }
+
+ weight = sd->weight;
+
+ // check item list
+ for( i = 0; i < count; i++ )
+ {// itemlist: <name id>.W <amount>.W <price>.L
+ unsigned short nameid, amount;
+ int price, idx;
+
+ nameid = RBUFW(itemlist,i*8+0);
+ amount = RBUFW(itemlist,i*8+2);
+ price = RBUFL(itemlist,i*8+4);
+
+ if( ( id = itemdb_exists(nameid) ) == NULL || amount == 0 )
+ {// invalid input
+ break;
+ }
+
+ if( price <= 0 || price > BUYINGSTORE_MAX_PRICE )
+ {// invalid price: unlike vending, items cannot be bought at 0 Zeny
+ break;
+ }
+
+ if( !id->flag.buyingstore || !itemdb_cantrade_sub(id, pc_isGM(sd), pc_isGM(sd)) || ( idx = pc_search_inventory(sd, nameid) ) == -1 )
+ {// restrictions: allowed, no character-bound items and at least one must be owned
+ break;
+ }
+
+ if( sd->status.inventory[idx].amount+amount > BUYINGSTORE_MAX_AMOUNT )
+ {// too many items of same kind
+ break;
+ }
+
+ if( i )
+ {// duplicate check. as the client does this too, only malicious intent should be caught here
+ ARR_FIND( 0, i, listidx, sd->buyingstore.items[i].nameid == nameid );
+ if( listidx != i )
+ {// duplicate
+ ShowWarning("buyingstore_create: Found duplicate item on buying list (nameid=%hu, amount=%hu, account_id=%d, char_id=%d).\n", nameid, amount, sd->status.account_id, sd->status.char_id);
+ break;
+ }
+ }
+
+ weight+= id->weight*amount;
+ sd->buyingstore.items[i].nameid = nameid;
+ sd->buyingstore.items[i].amount = amount;
+ sd->buyingstore.items[i].price = price;
+ }
+
+ if( i != count )
+ {// invalid item/amount/price
+ sd->buyingstore.slots = 0;
+ clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0);
+ return;
+ }
+
+ if( (sd->max_weight*90)/100 < weight )
+ {// not able to carry all wanted items without getting overweight (90%)
+ sd->buyingstore.slots = 0;
+ clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE_OVERWEIGHT, weight);
+ return;
+ }
+
+ // success
+ sd->state.buyingstore = true;
+ sd->buyer_id = buyingstore_getuid();
+ sd->buyingstore.zenylimit = zenylimit;
+ sd->buyingstore.slots = i; // store actual amount of items
+ safestrncpy(sd->message, storename, sizeof(sd->message));
+ clif_buyingstore_myitemlist(sd);
+ clif_buyingstore_entry(sd);
+}
+
+
+void buyingstore_close(struct map_session_data* sd)
+{
+ if( sd->state.buyingstore )
+ {
+ // invalidate data
+ sd->state.buyingstore = false;
+ memset(&sd->buyingstore, 0, sizeof(sd->buyingstore));
+
+ // notify other players
+ clif_buyingstore_disappear_entry(sd);
+ }
+}
+
+
+void buyingstore_open(struct map_session_data* sd, int account_id)
+{
+ struct map_session_data* pl_sd;
+
+ if( !battle_config.feature_buying_store || pc_istrading(sd) )
+ {// not allowed to sell
+ return;
+ }
+
+ if( !pc_can_give_items(pc_isGM(sd)) )
+ {// custom: GM is not allowed to sell
+ clif_displaymessage(sd->fd, msg_txt(246));
+ return;
+ }
+
+ if( ( pl_sd = map_id2sd(account_id) ) == NULL || !pl_sd->state.buyingstore )
+ {// not online or not buying
+ return;
+ }
+
+ // success
+ clif_buyingstore_itemlist(sd, pl_sd);
+}
+
+
+void buyingstore_trade(struct map_session_data* sd, int account_id, unsigned int buyer_id, const uint8* itemlist, unsigned int count)
+{
+ short blankslots[MAX_SLOTS]; // used when checking whether or not an item's card slots are blank
+ int zeny = 0;
+ unsigned int i, weight, listidx, k;
+ struct map_session_data* pl_sd;
+
+ if( count == 0 )
+ {// nothing to do
+ return;
+ }
+
+ if( !battle_config.feature_buying_store || pc_istrading(sd) )
+ {// not allowed to sell
+ clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
+ return;
+ }
+
+ if( !pc_can_give_items(pc_isGM(sd)) )
+ {// custom: GM is not allowed to sell
+ clif_displaymessage(sd->fd, msg_txt(246));
+ clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
+ return;
+ }
+
+ if( ( pl_sd = map_id2sd(account_id) ) == NULL || !pl_sd->state.buyingstore || pl_sd->buyer_id != buyer_id )
+ {// not online, not buying or not same store
+ clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
+ return;
+ }
+
+ if( pl_sd->status.zeny < pl_sd->buyingstore.zenylimit )
+ {// buyer lost zeny in the mean time? fix the limit
+ pl_sd->buyingstore.zenylimit = pl_sd->status.zeny;
+ }
+ weight = pl_sd->weight;
+ memset(blankslots, 0, sizeof(blankslots));
+
+ // check item list
+ for( i = 0; i < count; i++ )
+ {// itemlist: <index>.W <name id>.W <amount>.W
+ unsigned short nameid, amount;
+ int index;
+
+ index = RBUFW(itemlist,i*6+0)-2;
+ nameid = RBUFW(itemlist,i*6+2);
+ amount = RBUFW(itemlist,i*6+4);
+
+ if( i )
+ {// duplicate check. as the client does this too, only malicious intent should be caught here
+ ARR_FIND( 0, i, k, RBUFW(itemlist,k*6+0)-2 == index );
+ if( k != i )
+ {// duplicate
+ ShowWarning("buyingstore_trade: Found duplicate item on selling list (prevnameid=%hu, prevamount=%hu, nameid=%hu, amount=%hu, account_id=%d, char_id=%d).\n",
+ RBUFW(itemlist,k*6+2), RBUFW(itemlist,k*6+4), nameid, amount, sd->status.account_id, sd->status.char_id);
+ clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
+ return;
+ }
+ }
+
+ if( index < 0 || index >= ARRAYLENGTH(sd->status.inventory) || sd->inventory_data[index] == NULL || sd->status.inventory[index].nameid != nameid || sd->status.inventory[index].amount < amount )
+ {// invalid input
+ clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
+ return;
+ }
+
+ if( sd->status.inventory[index].expire_time || !itemdb_cantrade(&sd->status.inventory[index], pc_isGM(sd), pc_isGM(pl_sd)) || memcmp(sd->status.inventory[index].card, blankslots, sizeof(blankslots)) )
+ {// non-tradable item
+ clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
+ return;
+ }
+
+ ARR_FIND( 0, pl_sd->buyingstore.slots, listidx, pl_sd->buyingstore.items[listidx].nameid == nameid );
+ if( listidx == pl_sd->buyingstore.slots || pl_sd->buyingstore.items[listidx].amount == 0 )
+ {// there is no such item or the buyer has already bought all of them
+ clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
+ return;
+ }
+
+ if( pl_sd->buyingstore.items[listidx].amount < amount )
+ {// buyer does not need that much of the item
+ clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_COUNT, nameid);
+ return;
+ }
+
+ if( pc_checkadditem(pl_sd, nameid, amount) == ADDITEM_OVERAMOUNT )
+ {// buyer does not have enough space for this item
+ clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
+ return;
+ }
+
+ if( amount*(unsigned int)sd->inventory_data[index]->weight > pl_sd->max_weight-weight )
+ {// normally this is not supposed to happen, as the total weight is
+ // checked upon creation, but the buyer could have gained items
+ clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
+ return;
+ }
+ weight+= amount*sd->inventory_data[index]->weight;
+
+ if( amount*pl_sd->buyingstore.items[listidx].price > pl_sd->buyingstore.zenylimit-zeny )
+ {// buyer does not have enough zeny
+ clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_ZENY, nameid);
+ return;
+ }
+ zeny+= amount*pl_sd->buyingstore.items[listidx].price;
+ }
+
+ // process item list
+ for( i = 0; i < count; i++ )
+ {// itemlist: <index>.W <name id>.W <amount>.W
+ unsigned short nameid, amount;
+ int index;
+
+ index = RBUFW(itemlist,i*6+0)-2;
+ nameid = RBUFW(itemlist,i*6+2);
+ amount = RBUFW(itemlist,i*6+4);
+
+ ARR_FIND( 0, pl_sd->buyingstore.slots, listidx, pl_sd->buyingstore.items[listidx].nameid == nameid );
+ zeny = amount*pl_sd->buyingstore.items[listidx].price;
+
+ // log
+ if( log_config.enable_logs&LOG_BUYING_STORE )
+ {
+ log_pick_pc(sd, "B", nameid, -((int)amount), &sd->status.inventory[index]);
+ log_pick_pc(pl_sd, "B", nameid, amount, &sd->status.inventory[index]);
+ }
+ if( log_config.zeny )
+ log_zeny(sd, "B", pl_sd, zeny);
+
+ // move item
+ pc_additem(pl_sd, &sd->status.inventory[index], amount);
+ pc_delitem(sd, index, amount, 1, 0);
+ pl_sd->buyingstore.items[listidx].amount-= amount;
+
+ // pay up
+ pc_payzeny(pl_sd, zeny);
+ pc_getzeny(sd, zeny);
+ pl_sd->buyingstore.zenylimit-= zeny;
+
+ // notify clients
+ clif_buyingstore_delete_item(sd, index, amount, pl_sd->buyingstore.items[listidx].price);
+ clif_buyingstore_update_item(pl_sd, nameid, amount);
+ }
+
+ // check whether or not there is still something to buy
+ ARR_FIND( 0, pl_sd->buyingstore.slots, i, pl_sd->buyingstore.items[i].amount != 0 );
+ if( i == pl_sd->buyingstore.slots )
+ {// everything was bought
+ clif_buyingstore_trade_failed_buyer(pl_sd, BUYINGSTORE_TRADE_BUYER_NO_ITEMS);
+ buyingstore_close(pl_sd);
+ }
+ else if( pl_sd->buyingstore.zenylimit == 0 )
+ {// zeny limit reached
+ clif_buyingstore_trade_failed_buyer(pl_sd, BUYINGSTORE_TRADE_BUYER_ZENY);
+ buyingstore_close(pl_sd);
+ }
+}
diff --git a/src/map/buyingstore.h b/src/map/buyingstore.h
new file mode 100644
index 000000000..473fdb01a
--- /dev/null
+++ b/src/map/buyingstore.h
@@ -0,0 +1,29 @@
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#ifndef _BUYINGSTORE_H_
+#define _BUYINGSTORE_H_
+
+#define MAX_BUYINGSTORE_SLOTS 5
+
+struct s_buyingstore_item
+{
+ int price;
+ unsigned short amount;
+ unsigned short nameid;
+};
+
+struct s_buyingstore
+{
+ struct s_buyingstore_item items[MAX_BUYINGSTORE_SLOTS];
+ int zenylimit;
+ unsigned char slots;
+};
+
+bool buyingstore_setup(struct map_session_data* sd, unsigned char slots);
+void buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned char result, const char* storename, const uint8* itemlist, unsigned int count);
+void buyingstore_close(struct map_session_data* sd);
+void buyingstore_open(struct map_session_data* sd, int account_id);
+void buyingstore_trade(struct map_session_data* sd, int account_id, unsigned int buyer_id, const uint8* itemlist, unsigned int count);
+
+#endif // _BUYINGSTORE_H_
diff --git a/src/map/chat.c b/src/map/chat.c
index 96ec4c20d..4ba784b2e 100644
--- a/src/map/chat.c
+++ b/src/map/chat.c
@@ -69,6 +69,11 @@ int chat_createpcchat(struct map_session_data* sd, const char* title, const char
if( sd->chatID )
return 0; //Prevent people abusing the chat system by creating multiple chats, as pointed out by End of Exam. [Skotlex]
+ if( sd->vender_id || sd->state.buyingstore )
+ {// not chat, when you already have a store open
+ return 0;
+ }
+
if( map[sd->bl.m].flag.nochat )
{
clif_displaymessage(sd->fd, msg_txt(281));
@@ -108,7 +113,7 @@ int chat_joinchat(struct map_session_data* sd, int chatid, const char* pass)
nullpo_ret(sd);
cd = (struct chat_data*)map_id2bl(chatid);
- if( cd == NULL || cd->bl.type != BL_CHAT || cd->bl.m != sd->bl.m || sd->vender_id || sd->chatID || cd->users >= cd->limit )
+ if( cd == NULL || cd->bl.type != BL_CHAT || cd->bl.m != sd->bl.m || sd->vender_id || sd->state.buyingstore || sd->chatID || cd->users >= cd->limit )
{
clif_joinchatfail(sd,0);
return 0;
diff --git a/src/map/clif.c b/src/map/clif.c
index 59693d235..1bf87aec5 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -56,7 +56,10 @@ struct Clif_Config {
struct s_packet_db packet_db[MAX_PACKET_VER + 1][MAX_PACKET_DB + 1];
//Converts item type in case of pet eggs.
-#define itemtype(a) (a == IT_PETEGG)?IT_WEAPON:a
+inline int itemtype(int type)
+{
+ return ( type == IT_PETEGG ) ? IT_WEAPON : type;
+}
#define WBUFPOS(p,pos,x,y,dir) \
do { \
@@ -3644,6 +3647,9 @@ static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_d
if(dstsd->vender_id)
clif_showvendingboard(&dstsd->bl,dstsd->message,sd->fd);
+ if( dstsd->state.buyingstore )
+ clif_buyingstore_entry_single(sd, dstsd);
+
if(dstsd->spiritball > 0)
clif_spiritball_single(sd->fd, dstsd);
@@ -4072,6 +4078,8 @@ int clif_outsight(struct block_list *bl,va_list ap)
}
if(sd->vender_id)
clif_closevendingboard(bl,tsd->fd);
+ if( sd->state.buyingstore )
+ clif_buyingstore_disappear_entry_single(tsd, sd);
break;
case BL_ITEM:
clif_clearflooritem((struct flooritem_data*)bl,tsd->fd);
@@ -12851,7 +12859,7 @@ void clif_Auction_openwindow(struct map_session_data *sd)
{
int fd = sd->fd;
- if( sd->state.storage_flag || sd->vender_id || sd->state.trading )
+ if( sd->state.storage_flag || sd->vender_id || sd->state.buyingstore || sd->state.trading )
return;
WFIFOHEAD(fd,12);
@@ -14033,6 +14041,308 @@ void clif_showdigit(struct map_session_data* sd, unsigned char type, int value)
WFIFOSET(sd->fd, packet_len(0x1b1));
}
+
+/// Buying Store System
+///
+
+/// Opens preparation window for buying store (ZC_OPEN_BUYING_STORE)
+/// 0810 <slots>.B
+void clif_buyingstore_open(struct map_session_data* sd)
+{
+ int fd = sd->fd;
+
+ WFIFOHEAD(fd,packet_len(0x810));
+ WFIFOW(fd,0) = 0x810;
+ WFIFOB(fd,2) = sd->buyingstore.slots;
+ WFIFOSET(fd,packet_len(0x810));
+}
+
+
+/// Request to create a buying store (CZ_REQ_OPEN_BUYING_STORE)
+/// 0811 <packet len>.W <limit zeny>.L <result>.B <store name>.80B { <name id>.W <amount>.W <price>.L }*
+/// result:
+/// 0 = cancel
+/// 1 = open
+static void clif_parse_ReqOpenBuyingStore(int fd, struct map_session_data* sd)
+{
+ const unsigned int blocksize = 8;
+ uint8* itemlist;
+ char storename[MESSAGE_SIZE];
+ unsigned char result;
+ int zenylimit;
+ unsigned int count, packet_len;
+ struct s_packet_db* info = &packet_db[sd->packet_ver][RFIFOW(fd,0)];
+
+ packet_len = RFIFOW(fd,info->pos[0]);
+
+ // TODO: Make this check global for all variable length packets.
+ if( packet_len < 89 )
+ {// minimum packet length
+ ShowError("clif_parse_ReqOpenBuyingStore: Malformed packet (expected length=%u, length=%u, account_id=%d).\n", 89, packet_len, sd->bl.id);
+ return;
+ }
+
+ zenylimit = RFIFOL(fd,info->pos[1]);
+ result = RFIFOL(fd,info->pos[2]);
+ safestrncpy(storename, (const char*)RFIFOP(fd,info->pos[3]), sizeof(storename));
+ itemlist = RFIFOP(fd,info->pos[4]);
+
+ // so that buyingstore_create knows, how many elements it has access to
+ packet_len-= info->pos[4];
+
+ if( packet_len%blocksize )
+ {
+ ShowError("clif_parse_ReqOpenBuyingStore: Unexpected item list size %u (account_id=%d, block size=%u)\n", packet_len, sd->bl.id, blocksize);
+ return;
+ }
+ count = packet_len/blocksize;
+
+ buyingstore_create(sd, zenylimit, result, storename, itemlist, count);
+}
+
+
+/// Notification, that the requested buying store could not be created (ZC_FAILED_OPEN_BUYING_STORE_TO_BUYER)
+/// 0812 <result>.W <total weight>.L
+/// result:
+/// 1 = "Failed to open buying store." (0x6cd, MSI_BUYINGSTORE_OPEN_FAILED)
+/// 2 = "Total amount of then possessed items exceeds the weight limit by <weight/10-maxweight*90%>. Please re-enter." (0x6ce, MSI_BUYINGSTORE_OVERWEIGHT)
+/// 8 = "No sale (purchase) information available." (0x705)
+/// other = nothing
+void clif_buyingstore_open_failed(struct map_session_data* sd, unsigned short result, unsigned int weight)
+{
+ int fd = sd->fd;
+
+ WFIFOHEAD(fd,packet_len(0x812));
+ WFIFOW(fd,0) = 0x812;
+ WFIFOW(fd,2) = result;
+ WFIFOL(fd,4) = weight;
+ WFIFOSET(fd,packet_len(0x812));
+}
+
+
+/// Notification, that the requested buying store was created (ZC_MYITEMLIST_BUYING_STORE)
+/// 0813 <packet len>.W <account id>.L <limit zeny>.L { <price>.L <count>.W <type>.B <name id>.W }*
+void clif_buyingstore_myitemlist(struct map_session_data* sd)
+{
+ int fd = sd->fd;
+ unsigned int i;
+
+ WFIFOHEAD(fd,12+sd->buyingstore.slots*9);
+ WFIFOW(fd,0) = 0x813;
+ WFIFOW(fd,2) = 12+sd->buyingstore.slots*9;
+ WFIFOL(fd,4) = sd->bl.id;
+ WFIFOL(fd,8) = sd->buyingstore.zenylimit;
+
+ for( i = 0; i < sd->buyingstore.slots; i++ )
+ {
+ WFIFOL(fd,12+i*9) = sd->buyingstore.items[i].price;
+ WFIFOW(fd,16+i*9) = sd->buyingstore.items[i].amount;
+ WFIFOB(fd,18+i*9) = itemtype(itemdb_type(sd->buyingstore.items[i].nameid));
+ WFIFOW(fd,19+i*9) = sd->buyingstore.items[i].nameid;
+ }
+
+ WFIFOSET(fd,WFIFOW(fd,2));
+}
+
+
+/// Notifies clients in area of a buying store (ZC_BUYING_STORE_ENTRY)
+/// 0814 <account id>.L <store name>.80B
+void clif_buyingstore_entry(struct map_session_data* sd)
+{
+ uint8 buf[86];
+
+ WBUFW(buf,0) = 0x814;
+ WBUFL(buf,2) = sd->bl.id;
+ memcpy(WBUFP(buf,6), sd->message, MESSAGE_SIZE);
+
+ clif_send(buf, packet_len(0x814), &sd->bl, AREA_WOS);
+}
+void clif_buyingstore_entry_single(struct map_session_data* sd, struct map_session_data* pl_sd)
+{
+ int fd = sd->fd;
+
+ WFIFOHEAD(fd,packet_len(0x814));
+ WFIFOW(fd,0) = 0x814;
+ WFIFOL(fd,2) = pl_sd->bl.id;
+ memcpy(WFIFOP(fd,6), pl_sd->message, MESSAGE_SIZE);
+ WFIFOSET(fd,packet_len(0x814));
+}
+
+
+/// Request to close own buying store (CZ_REQ_CLOSE_BUYING_STORE)
+/// 0815
+static void clif_parse_ReqCloseBuyingStore(int fd, struct map_session_data* sd)
+{
+ buyingstore_close(sd);
+}
+
+
+/// Notifies clients in area that a buying store was closed (ZC_DISAPPEAR_BUYING_STORE_ENTRY)
+/// 0816 <account id>.L
+void clif_buyingstore_disappear_entry(struct map_session_data* sd)
+{
+ uint8 buf[6];
+
+ WBUFW(buf,0) = 0x816;
+ WBUFL(buf,2) = sd->bl.id;
+
+ clif_send(buf, packet_len(0x816), &sd->bl, AREA_WOS);
+}
+void clif_buyingstore_disappear_entry_single(struct map_session_data* sd, struct map_session_data* pl_sd)
+{
+ int fd = sd->fd;
+
+ WFIFOHEAD(fd,packet_len(0x816));
+ WFIFOW(fd,0) = 0x816;
+ WFIFOL(fd,2) = pl_sd->bl.id;
+ WFIFOSET(fd,packet_len(0x816));
+}
+
+
+/// Request to open someone else's buying store (CZ_REQ_CLICK_TO_BUYING_STORE)
+/// 0817 <account id>.L
+static void clif_parse_ReqClickBuyingStore(int fd, struct map_session_data* sd)
+{
+ int account_id;
+
+ account_id = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
+
+ buyingstore_open(sd, account_id);
+}
+
+
+/// Sends buying store item list (ZC_ACK_ITEMLIST_BUYING_STORE)
+/// 0818 <packet len>.W <account id>.L <store id>.L <limit zeny>.L { <price>.L <amount>.W <type>.B <name id>.W }*
+void clif_buyingstore_itemlist(struct map_session_data* sd, struct map_session_data* pl_sd)
+{
+ int fd = sd->fd;
+ unsigned int i;
+
+ WFIFOHEAD(fd,16+pl_sd->buyingstore.slots*9);
+ WFIFOW(fd,0) = 0x818;
+ WFIFOW(fd,2) = 16+pl_sd->buyingstore.slots*9;
+ WFIFOL(fd,4) = pl_sd->bl.id;
+ WFIFOL(fd,8) = pl_sd->buyer_id;
+ WFIFOL(fd,12) = pl_sd->buyingstore.zenylimit;
+
+ for( i = 0; i < pl_sd->buyingstore.slots; i++ )
+ {
+ WFIFOL(fd,16+i*9) = pl_sd->buyingstore.items[i].price;
+ WFIFOW(fd,20+i*9) = pl_sd->buyingstore.items[i].amount; // TODO: Figure out, if no longer needed items (amount == 0) are listed on official.
+ WFIFOB(fd,22+i*9) = itemtype(itemdb_type(pl_sd->buyingstore.items[i].nameid));
+ WFIFOW(fd,23+i*9) = pl_sd->buyingstore.items[i].nameid;
+ }
+
+ WFIFOSET(fd,WFIFOW(fd,2));
+}
+
+
+/// Request to sell items to a buying store (CZ_REQ_TRADE_BUYING_STORE)
+/// 0819 <packet len>.W <account id>.L <store id>.L { <index>.W <name id>.W <amount>.W }*
+static void clif_parse_ReqTradeBuyingStore(int fd, struct map_session_data* sd)
+{
+ const unsigned int blocksize = 6;
+ uint8* itemlist;
+ int account_id;
+ unsigned int count, packet_len, buyer_id;
+ struct s_packet_db* info = &packet_db[sd->packet_ver][RFIFOW(fd,0)];
+
+ packet_len = RFIFOW(fd,info->pos[0]);
+
+ if( packet_len < 12 )
+ {// minimum packet length
+ ShowError("clif_parse_ReqTradeBuyingStore: Malformed packet (expected length=%u, length=%u, account_id=%d).\n", 12, packet_len, sd->bl.id);
+ return;
+ }
+
+ account_id = RFIFOL(fd,info->pos[1]);
+ buyer_id = RFIFOL(fd,info->pos[2]);
+ itemlist = RFIFOP(fd,info->pos[3]);
+
+ // so that buyingstore_trade knows, how many elements it has access to
+ packet_len-= info->pos[3];
+
+ if( packet_len%blocksize )
+ {
+ ShowError("clif_parse_ReqTradeBuyingStore: Unexpected item list size %u (account_id=%d, buyer_id=%d, block size=%u)\n", packet_len, sd->bl.id, account_id, blocksize);
+ return;
+ }
+ count = packet_len/blocksize;
+
+ buyingstore_trade(sd, account_id, buyer_id, itemlist, count);
+}
+
+
+/// Notifies the buyer, that the buying store has been closed due to a post-trade condition (ZC_FAILED_TRADE_BUYING_STORE_TO_BUYER)
+/// 081a <result>.W
+/// result:
+/// 3 = "All items within the buy limit were purchased." (0x6cf, MSI_BUYINGSTORE_TRADE_OVERLIMITZENY)
+/// 4 = "All items were purchased." (0x6d0, MSI_BUYINGSTORE_TRADE_BUYCOMPLETE)
+/// other = nothing
+void clif_buyingstore_trade_failed_buyer(struct map_session_data* sd, short result)
+{
+ int fd = sd->fd;
+
+ WFIFOHEAD(fd,packet_len(0x81a));
+ WFIFOW(fd,0) = 0x81a;
+ WFIFOW(fd,2) = result;
+ WFIFOSET(fd,packet_len(0x81a));
+}
+
+
+/// Updates the zeny limit and an item in the buying store item list (ZC_UPDATE_ITEM_FROM_BUYING_STORE)
+/// 081b <name id>.W <amount>.W <limit zeny>.L
+void clif_buyingstore_update_item(struct map_session_data* sd, unsigned short nameid, unsigned short amount)
+{
+ int fd = sd->fd;
+
+ WFIFOHEAD(fd,packet_len(0x81b));
+ WFIFOW(fd,0) = 0x81b;
+ WFIFOW(fd,2) = nameid;
+ WFIFOW(fd,4) = amount; // amount of nameid received
+ WFIFOW(fd,6) = sd->buyingstore.zenylimit;
+ WFIFOSET(fd,packet_len(0x81b));
+}
+
+
+/// Deletes item from inventory, that was sold to a buying store (ZC_ITEM_DELETE_BUYING_STORE)
+/// 081c <index>.W <amount>.W <price>.L
+/// message:
+/// "%s (%d) were sold at %dz." (0x6d2, MSI_BUYINGSTORE_TRADE_SELLCOMPLETE)
+///
+/// @note This function has to be called _instead_ of clif_delitem/clif_dropitem.
+void clif_buyingstore_delete_item(struct map_session_data* sd, short index, unsigned short amount, int price)
+{
+ int fd = sd->fd;
+
+ WFIFOHEAD(fd,packet_len(0x81c));
+ WFIFOW(fd,0) = 0x81c;
+ WFIFOW(fd,2) = index+2;
+ WFIFOW(fd,4) = amount;
+ WFIFOL(fd,6) = price; // price per item, client calculates total Zeny by itself
+ WFIFOSET(fd,packet_len(0x81c));
+}
+
+
+/// Notifies the seller, that a buying store trade failed (ZC_FAILED_TRADE_BUYING_STORE_TO_SELLER)
+/// 0824 <result>.W <name id>.W
+/// result:
+/// 5 = "The deal has failed." (0x39, MSI_DEAL_FAIL)
+/// 6 = "The trade failed, because the entered amount of item %s is higher, than the buyer is willing to buy." (0x6d3, MSI_BUYINGSTORE_TRADE_OVERCOUNT)
+/// 7 = "The trade failed, because the buyer is lacking required balance." (0x6d1, MSI_BUYINGSTORE_TRADE_LACKBUYERZENY)
+/// other = nothing
+void clif_buyingstore_trade_failed_seller(struct map_session_data* sd, short result, unsigned short nameid)
+{
+ int fd = sd->fd;
+
+ WFIFOHEAD(fd,packet_len(0x824));
+ WFIFOW(fd,0) = 0x824;
+ WFIFOW(fd,2) = result;
+ WFIFOW(fd,4) = nameid;
+ WFIFOSET(fd,packet_len(0x824));
+}
+
+
/*==========================================
* パケットデバッグ
*------------------------------------------*/
@@ -14435,8 +14745,8 @@ static int packetdb_readdb(void)
#else // for Party booking ( PACKETVER >= 20091229 )
-1, -1, 18, 4, 8, 6, 2, 4, 14, 50, 18, 6, 2, 3, 14, 20,
#endif
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 3, -1, 8, -1, 86, 2, 6, 6, -1, -1, 4, 10, 10, 0, 0, 0,
+ 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
struct {
@@ -14628,6 +14938,11 @@ static int packetdb_readdb(void)
{clif_parse_PartyBookingDeleteReq,"bookingdelreq"},
#endif
{clif_parse_PVPInfo,"pvpinfo"},
+ // Buying Store
+ {clif_parse_ReqOpenBuyingStore,"reqopenbuyingstore"},
+ {clif_parse_ReqCloseBuyingStore,"reqclosebuyingstore"},
+ {clif_parse_ReqClickBuyingStore,"reqclickbuyingstore"},
+ {clif_parse_ReqTradeBuyingStore,"reqtradebuyingstore"},
{NULL,NULL}
};
diff --git a/src/map/clif.h b/src/map/clif.h
index 50dc76c72..67516e538 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -605,4 +605,18 @@ void clif_PartyBookingInsertNotify(struct map_session_data* sd, struct party_boo
void clif_showdigit(struct map_session_data* sd, unsigned char type, int value);
+/// Buying Store System
+void clif_buyingstore_open(struct map_session_data* sd);
+void clif_buyingstore_open_failed(struct map_session_data* sd, unsigned short result, unsigned int weight);
+void clif_buyingstore_myitemlist(struct map_session_data* sd);
+void clif_buyingstore_entry(struct map_session_data* sd);
+void clif_buyingstore_entry_single(struct map_session_data* sd, struct map_session_data* pl_sd);
+void clif_buyingstore_disappear_entry(struct map_session_data* sd);
+void clif_buyingstore_disappear_entry_single(struct map_session_data* sd, struct map_session_data* pl_sd);
+void clif_buyingstore_itemlist(struct map_session_data* sd, struct map_session_data* pl_sd);
+void clif_buyingstore_trade_failed_buyer(struct map_session_data* sd, short result);
+void clif_buyingstore_update_item(struct map_session_data* sd, unsigned short nameid, unsigned short amount);
+void clif_buyingstore_delete_item(struct map_session_data* sd, short index, unsigned short amount, int price);
+void clif_buyingstore_trade_failed_seller(struct map_session_data* sd, short result, unsigned short nameid);
+
#endif /* _CLIF_H_ */
diff --git a/src/map/itemdb.c b/src/map/itemdb.c
index 98f9a90d1..d8a8bb2cc 100644
--- a/src/map/itemdb.c
+++ b/src/map/itemdb.c
@@ -663,6 +663,33 @@ static bool itemdb_read_itemdelay(char* str[], int columns, int current)
return true;
}
+
+/// Reads items allowed to be sold in buying stores
+static bool itemdb_read_buyingstore(char* fields[], int columns, int current)
+{// <nameid>
+ int nameid;
+ struct item_data* id;
+
+ nameid = atoi(fields[0]);
+
+ if( ( id = itemdb_exists(nameid) ) == NULL )
+ {
+ ShowWarning("itemdb_read_buyingstore: Invalid item id %d.\n", nameid);
+ return false;
+ }
+
+ if( !itemdb_isstackable2(id) )
+ {
+ ShowWarning("itemdb_read_buyingstore: Non-stackable item id %d cannot be enabled for buying store.\n", nameid);
+ return false;
+ }
+
+ id->flag.buyingstore = true;
+
+ return true;
+}
+
+
/*======================================
* Applies gender restrictions according to settings. [Skotlex]
*======================================*/
@@ -979,6 +1006,7 @@ static void itemdb_read(void)
sv_readdb(db_path, "item_noequip.txt", ',', 2, 2, -1, &itemdb_read_noequip);
sv_readdb(db_path, "item_trade.txt", ',', 3, 3, -1, &itemdb_read_itemtrade);
sv_readdb(db_path, "item_delay.txt", ',', 2, 2, MAX_ITEMDELAYS, &itemdb_read_itemdelay);
+ sv_readdb(db_path, "item_buyingstore.txt", ',', 1, 1, -1, &itemdb_read_buyingstore);
}
/*==========================================
diff --git a/src/map/itemdb.h b/src/map/itemdb.h
index b5bcb84ea..463061175 100644
--- a/src/map/itemdb.h
+++ b/src/map/itemdb.h
@@ -76,6 +76,7 @@ struct item_data {
unsigned delay_consume : 1; // Signifies items that are not consumed immediately upon double-click [Skotlex]
unsigned trade_restriction : 7; //Item restrictions mask [Skotlex]
unsigned autoequip: 1;
+ unsigned buyingstore : 1;
} flag;
short gm_lv_trade_override; //GM-level to override trade_restriction
};
diff --git a/src/map/log.h b/src/map/log.h
index 9dfc0c0ea..f88236489 100644
--- a/src/map/log.h
+++ b/src/map/log.h
@@ -36,9 +36,10 @@ typedef enum log_what {
LOG_USED_ITEMS = 0x0100, // used by player
LOG_MVP_PRIZE = 0x0200,
LOG_COMMAND_ITEMS = 0x0400, // created/deleted through @/# commands
- LOG_STORAGE_ITEMS = 0x0800, // placed/retrieved from storage
- LOG_GSTORAGE_ITEMS = 0x1000, // placed/retrieved from guild storage
- LOG_MAILS = 0x2000 // mail system transactions
+ LOG_STORAGE_ITEMS = 0x0800, // placed/retrieved from storage
+ LOG_GSTORAGE_ITEMS = 0x1000, // placed/retrieved from guild storage
+ LOG_MAILS = 0x2000, // mail system transactions
+ LOG_BUYING_STORE = 0x4000, // buying store transactions
} log_what;
extern struct Log_Config {
diff --git a/src/map/mail.c b/src/map/mail.c
index f0869185a..c866bfb60 100644
--- a/src/map/mail.c
+++ b/src/map/mail.c
@@ -162,7 +162,7 @@ int mail_openmail(struct map_session_data *sd)
{
nullpo_ret(sd);
- if( sd->state.storage_flag || sd->vender_id || sd->state.trading )
+ if( sd->state.storage_flag || sd->vender_id || sd->state.buyingstore || sd->state.trading )
return 0;
clif_Mail_window(sd->fd, 0);
diff --git a/src/map/pc.h b/src/map/pc.h
index c48defbf5..328e43047 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -7,6 +7,7 @@
#include "../common/mmo.h" // JOB_*, MAX_FAME_LIST, struct fame_list, struct mmo_charstatus
#include "../common/timer.h" // INVALID_TIMER
#include "battle.h" // battle_config
+#include "buyingstore.h" // struct s_buyingstore
#include "itemdb.h" // MAX_ITEMGROUP
#include "map.h" // RC_MAX
#include "pc.h" // struct map_session_data
@@ -128,6 +129,7 @@ struct map_session_data {
unsigned doridori : 1;
unsigned ignoreAll : 1;
unsigned debug_remove_map : 1; // temporary state to track double remove_map's [FlavioJS]
+ unsigned buyingstore : 1;
unsigned short autoloot;
unsigned short autolootid; // [Zephyrus]
unsigned noks : 3; // [Zeph Kill Steal Protection]
@@ -356,6 +358,9 @@ struct map_session_data {
char message[MESSAGE_SIZE];
struct s_vending vending[MAX_VENDING];
+ unsigned int buyer_id; // uid of open buying store
+ struct s_buyingstore buyingstore;
+
struct pet_data *pd;
struct homun_data *hd; // [blackhole89]
struct mercenary_data *md;
@@ -413,8 +418,8 @@ struct map_session_data {
const char* debug_func;
};
-//Update this max as necessary. 54 is the value needed for Super Baby currently
-#define MAX_SKILL_TREE 54
+//Update this max as necessary. 55 is the value needed for Super Baby currently
+#define MAX_SKILL_TREE 55
//Total number of classes (for data storage)
#define CLASS_COUNT (JOB_MAX - JOB_NOVICE_HIGH + JOB_MAX_BASIC)
@@ -515,9 +520,9 @@ extern int duel_count;
#define pc_setsit(sd) ( (sd)->state.dead_sit = (sd)->vd.dead_sit = 2 )
#define pc_isdead(sd) ( (sd)->state.dead_sit == 1 )
#define pc_issit(sd) ( (sd)->vd.dead_sit == 2 )
-#define pc_isidle(sd) ( (sd)->chatID || (sd)->vender_id || DIFF_TICK(last_tick, (sd)->idletime) >= battle_config.idle_no_share )
-#define pc_istrading(sd) ( (sd)->npc_id || (sd)->vender_id || (sd)->state.trading )
-#define pc_cant_act(sd) ( (sd)->npc_id || (sd)->vender_id || (sd)->chatID || (sd)->sc.opt1 || (sd)->state.trading || (sd)->state.storage_flag )
+#define pc_isidle(sd) ( (sd)->chatID || (sd)->vender_id || (sd)->state.buyingstore || DIFF_TICK(last_tick, (sd)->idletime) >= battle_config.idle_no_share )
+#define pc_istrading(sd) ( (sd)->npc_id || (sd)->vender_id || (sd)->state.buyingstore || (sd)->state.trading )
+#define pc_cant_act(sd) ( (sd)->npc_id || (sd)->vender_id || (sd)->state.buyingstore || (sd)->chatID || (sd)->sc.opt1 || (sd)->state.trading || (sd)->state.storage_flag )
#define pc_setdir(sd,b,h) ( (sd)->ud.dir = (b) ,(sd)->head_dir = (h) )
#define pc_setchatid(sd,n) ( (sd)->chatID = n )
#define pc_ishiding(sd) ( (sd)->sc.option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) )
diff --git a/src/map/script.c b/src/map/script.c
index bbb0041de..d66edcd84 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -14807,6 +14807,23 @@ BUILDIN_FUNC(pushpc)
return 0;
}
+
+/// Invokes buying store preparation window
+/// buyingstore <slots>;
+BUILDIN_FUNC(buyingstore)
+{
+ struct map_session_data* sd;
+
+ if( ( sd = script_rid2sd(st) ) == NULL )
+ {
+ return 0;
+ }
+
+ buyingstore_setup(sd, script_getnum(st,2));
+ return 0;
+}
+
+
// declarations that were supposed to be exported from npc_chat.c
#ifdef PCRE_SUPPORT
BUILDIN_FUNC(defpattern);
@@ -15168,6 +15185,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(areamobuseskill,"siiiiviiiii"),
BUILDIN_DEF(progressbar,"si"),
BUILDIN_DEF(pushpc,"ii"),
+ BUILDIN_DEF(buyingstore,"i"),
// WoE SE
BUILDIN_DEF(agitstart2,""),
BUILDIN_DEF(agitend2,""),
diff --git a/src/map/skill.c b/src/map/skill.c
index ffb5a1826..160beeaef 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -5692,6 +5692,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case ALL_WEWISH:
clif_skill_nodamage(src,bl,skillid,skilllv,1);
break;
+ case ALL_BUYING_STORE:
+ if( sd )
+ {// players only, skill allows 5 buying slots
+ clif_skill_nodamage(src, bl, skillid, skilllv, buyingstore_setup(sd, MAX_BUYINGSTORE_SLOTS));
+ }
+ break;
default:
ShowWarning("skill_castend_nodamage_id: Unknown skill used:%d\n",skillid);
clif_skill_nodamage(src,bl,skillid,skilllv,1);
diff --git a/src/map/trade.c b/src/map/trade.c
index ba01826f2..bedbb9451 100644
--- a/src/map/trade.c
+++ b/src/map/trade.c
@@ -138,8 +138,8 @@ void trade_tradeack(struct map_session_data *sd, int type)
}
//Check if you can start trade.
- if (sd->npc_id || sd->vender_id || sd->state.storage_flag ||
- tsd->npc_id || tsd->vender_id || tsd->state.storage_flag)
+ if (sd->npc_id || sd->vender_id || sd->state.buyingstore || sd->state.storage_flag ||
+ tsd->npc_id || tsd->vender_id || tsd->state.buyingstore || tsd->state.storage_flag)
{ //Fail
clif_tradestart(sd, 2);
clif_tradestart(tsd, 2);
diff --git a/src/map/unit.c b/src/map/unit.c
index 7abfde12b..3f2b2094f 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -803,6 +803,7 @@ int unit_can_move(struct block_list *bl)
if (sd && (
pc_issit(sd) ||
sd->vender_id ||
+ sd->state.buyingstore ||
sd->state.blockedmove
))
return 0; //Can't move
@@ -1872,6 +1873,7 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file,
trade_tradecancel(sd);
if(sd->vender_id)
vending_closevending(sd);
+ buyingstore_close(sd);
if(sd->state.storage_flag == 1)
storage_storage_quit(sd,0);
else if (sd->state.storage_flag == 2)
diff --git a/vcproj-10/map-server_sql.vcxproj b/vcproj-10/map-server_sql.vcxproj
index d8a35698e..201c0bfb6 100644
--- a/vcproj-10/map-server_sql.vcxproj
+++ b/vcproj-10/map-server_sql.vcxproj
@@ -146,6 +146,7 @@
<ClInclude Include="..\src\map\atcommand.h" />
<ClInclude Include="..\src\map\battle.h" />
<ClInclude Include="..\src\map\battleground.h" />
+ <ClInclude Include="..\src\map\buyingstore.h" />
<ClInclude Include="..\src\map\chat.h" />
<ClInclude Include="..\src\map\chrif.h" />
<ClInclude Include="..\src\map\clif.h" />
@@ -195,6 +196,7 @@
<ClCompile Include="..\src\map\atcommand.c" />
<ClCompile Include="..\src\map\battle.c" />
<ClCompile Include="..\src\map\battleground.c" />
+ <ClCompile Include="..\src\map\buyingstore.c" />
<ClCompile Include="..\src\map\chat.c" />
<ClCompile Include="..\src\map\chrif.c" />
<ClCompile Include="..\src\map\clif.c" />
diff --git a/vcproj-10/map-server_txt.vcxproj b/vcproj-10/map-server_txt.vcxproj
index 3efded728..5c1847a0e 100644
--- a/vcproj-10/map-server_txt.vcxproj
+++ b/vcproj-10/map-server_txt.vcxproj
@@ -125,6 +125,7 @@
<ClCompile Include="..\src\map\atcommand.c" />
<ClCompile Include="..\src\map\battle.c" />
<ClCompile Include="..\src\map\battleground.c" />
+ <ClCompile Include="..\src\map\buyingstore.c" />
<ClCompile Include="..\src\map\chat.c" />
<ClCompile Include="..\src\map\chrif.c" />
<ClCompile Include="..\src\map\clif.c" />
@@ -174,6 +175,7 @@
<ClInclude Include="..\src\map\atcommand.h" />
<ClInclude Include="..\src\map\battle.h" />
<ClInclude Include="..\src\map\battleground.h" />
+ <ClInclude Include="..\src\map\buyingstore.h" />
<ClInclude Include="..\src\map\chat.h" />
<ClInclude Include="..\src\map\chrif.h" />
<ClInclude Include="..\src\map\clif.h" />
diff --git a/vcproj-6/map-server_sql.dsp b/vcproj-6/map-server_sql.dsp
index 629fe4639..afc259bc7 100644
--- a/vcproj-6/map-server_sql.dsp
+++ b/vcproj-6/map-server_sql.dsp
@@ -231,6 +231,14 @@ SOURCE=..\src\map\battleground.h
# End Source File
# Begin Source File
+SOURCE=..\src\map\buyingstore.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\map\buyingstore.h
+# End Source File
+# Begin Source File
+
SOURCE=..\src\map\chat.c
# End Source File
# Begin Source File
diff --git a/vcproj-6/map-server_txt.dsp b/vcproj-6/map-server_txt.dsp
index 1359adc15..404af83ab 100644
--- a/vcproj-6/map-server_txt.dsp
+++ b/vcproj-6/map-server_txt.dsp
@@ -211,6 +211,10 @@ SOURCE=..\src\map\battleground.c
# End Source File
# Begin Source File
+SOURCE=..\src\map\buyingstore.c
+# End Source File
+# Begin Source File
+
SOURCE=..\src\map\chat.c
# End Source File
# Begin Source File
@@ -335,6 +339,10 @@ SOURCE=..\src\map\battleground.h
# End Source File
# Begin Source File
+SOURCE=..\src\map\buyingstore.h
+# End Source File
+# Begin Source File
+
SOURCE=..\src\map\chat.h
# End Source File
# Begin Source File
diff --git a/vcproj-7.1/map-server_sql.vcproj b/vcproj-7.1/map-server_sql.vcproj
index de441773c..e820ec563 100644
--- a/vcproj-7.1/map-server_sql.vcproj
+++ b/vcproj-7.1/map-server_sql.vcproj
@@ -167,6 +167,12 @@
RelativePath="..\src\map\battleground.h">
</File>
<File
+ RelativePath="..\src\map\buyingstore.c">
+ </File>
+ <File
+ RelativePath="..\src\map\buyingstore.h">
+ </File>
+ <File
RelativePath="..\src\map\chat.c">
</File>
<File
diff --git a/vcproj-7.1/map-server_txt.vcproj b/vcproj-7.1/map-server_txt.vcproj
index f91248859..998f5b916 100644
--- a/vcproj-7.1/map-server_txt.vcproj
+++ b/vcproj-7.1/map-server_txt.vcproj
@@ -167,6 +167,12 @@
RelativePath="..\src\map\battleground.h">
</File>
<File
+ RelativePath="..\src\map\buyingstore.c">
+ </File>
+ <File
+ RelativePath="..\src\map\buyingstore.h">
+ </File>
+ <File
RelativePath="..\src\map\chat.c">
</File>
<File
diff --git a/vcproj-8/map-server_sql.vcproj b/vcproj-8/map-server_sql.vcproj
index f1b1b6cd6..2a29782de 100644
--- a/vcproj-8/map-server_sql.vcproj
+++ b/vcproj-8/map-server_sql.vcproj
@@ -374,6 +374,13 @@
<File
RelativePath="..\src\map\battleground.h"
>
+ <File
+ RelativePath="..\src\map\buyingstore.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\map\buyingstore.h"
+ >
</File>
<File
RelativePath="..\src\map\chat.c"
diff --git a/vcproj-8/map-server_txt.vcproj b/vcproj-8/map-server_txt.vcproj
index 4de699109..2d51d6eb7 100644
--- a/vcproj-8/map-server_txt.vcproj
+++ b/vcproj-8/map-server_txt.vcproj
@@ -227,6 +227,14 @@
>
</File>
<File
+ RelativePath="..\src\map\buyingstore.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\map\buyingstore.h"
+ >
+ </File>
+ <File
RelativePath="..\src\map\chat.c"
>
</File>
diff --git a/vcproj-9/map-server_sql.vcproj b/vcproj-9/map-server_sql.vcproj
index e147ca137..0dd152f88 100644
--- a/vcproj-9/map-server_sql.vcproj
+++ b/vcproj-9/map-server_sql.vcproj
@@ -375,6 +375,14 @@
>
</File>
<File
+ RelativePath="..\src\map\buyingstore.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\map\buyingstore.c"
+ >
+ </File>
+ <File
RelativePath="..\src\map\chat.c"
>
</File>
diff --git a/vcproj-9/map-server_txt.vcproj b/vcproj-9/map-server_txt.vcproj
index d4ea93a89..14daabc20 100644
--- a/vcproj-9/map-server_txt.vcproj
+++ b/vcproj-9/map-server_txt.vcproj
@@ -226,6 +226,14 @@
>
</File>
<File
+ RelativePath="..\src\map\buyingstore.c"
+ >
+ </File>
+ <File
+ RelativePath="..\src\map\buyingstore.h"
+ >
+ </File>
+ <File
RelativePath="..\src\map\chat.c"
>
</File>