Difference between revisions of "A Shop Like Thing"
m (→A Shop Like Thing) |
(→A Shop Like Thing: Suggest using the Colosseum shop, remove placeholders that were never finished) |
||
(3 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
+ | {{WML Tags}} | ||
+ | |||
== A Shop Like Thing == | == A Shop Like Thing == | ||
− | + | In this page you can see different techniques of creating a shop. | |
+ | |||
+ | == Example implementations == | ||
+ | |||
+ | There's a [https://r.wesnoth.org/t50024 discussion thread] that started in 2019 (Wesnoth 1.14). | ||
+ | |||
+ | === The Colosseum add-on's shop === | ||
+ | |||
+ | The add-on [https://r.wesnoth.org/t27671 Colosseum] has a shop that's intended to be usable by other add-ons. Basic usage is given in the ''readme'' file in the add-on. | ||
+ | |||
+ | === Simple === | ||
+ | Use this macro to place a moveto event in your scenario that defines a magic-items shop. Argument is a [[StandardLocationFilter]]. | ||
− | + | Used macros: | |
+ | * VARIABLE_CONDITIONAL (from file [http://www.wesnoth.org/macro-reference.xhtml#file:utils.cfg utils.cfg]) | ||
+ | * CLEAR_VARIABLE (from file [http://www.wesnoth.org/macro-reference.xhtml#file:utils.cfg utils.cfg]) | ||
+ | * WEAPON_SPECIAL_MAGICAL (from file[http://www.wesnoth.org/macro-reference.xhtml#file:abilities.cfg abilities.cfg]) | ||
− | #define | + | #define CREATE_SIMPLE_SHOP FILTER |
[event] | [event] | ||
name=moveto | name=moveto | ||
first_time_only=no | first_time_only=no | ||
[filter] | [filter] | ||
+ | # this is not a macro. It is a argument token, | ||
+ | # which will be substituted with argument value | ||
{FILTER} | {FILTER} | ||
[/filter] | [/filter] | ||
[store_gold] | [store_gold] | ||
side=$side_number | side=$side_number | ||
− | variable=gold | + | variable=css_gold |
+ | # it is bad idea to use simple variable names like "gold" inside macro | ||
+ | # because you can overwrite values of variables, | ||
+ | # which was defined outside of this macro and was supposed to be used for | ||
+ | # anything else. To prevent any side effects, preceed macro-specific variables | ||
+ | # with abbreviation of macro name | ||
[/store_gold] | [/store_gold] | ||
+ | # this is easiest way to create menu in the game. | ||
+ | # you just define each value and player sees them anytime he trigger this event | ||
[message] | [message] | ||
speaker=narrator | speaker=narrator | ||
Line 23: | Line 48: | ||
[option] | [option] | ||
message=_ "140 GP: Sharpen Melee Weapon, damage:+2" | message=_ "140 GP: Sharpen Melee Weapon, damage:+2" | ||
+ | [show_if] | ||
+ | {VARIABLE_CONDITIONAL gold greater_than 140} | ||
+ | [/show_if] | ||
[command] | [command] | ||
− | [ | + | [gold] |
− | + | amount=-140 | |
− | + | side=$side_number | |
− | + | [/gold] | |
− | + | [object] | |
− | + | silent = yes | |
− | + | [effect] | |
− | + | apply_to=attack | |
− | + | # You need to specify filter for your effect | |
− | + | # but you should't use [filter] tags | |
− | + | # [filter] | |
− | + | range=melee | |
− | + | # [/filter] | |
− | + | increase_damage=2 | |
− | + | [/effect] | |
− | + | [/object] | |
− | |||
− | [/ | ||
− | [/ | ||
[/command] | [/command] | ||
[/option] | [/option] | ||
Line 48: | Line 73: | ||
[option] | [option] | ||
message=_ "150 GP: Enchance Ranged Weapon, damage +2" | message=_ "150 GP: Enchance Ranged Weapon, damage +2" | ||
+ | [show_if] | ||
+ | {VARIABLE_CONDITIONAL gold greater_than 150} | ||
+ | [/show_if] | ||
[command] | [command] | ||
− | [ | + | [gold] |
− | + | side=$side_number | |
− | + | amount=-150 | |
− | + | [/gold] | |
− | + | [object] | |
− | + | silent = yes | |
− | + | [effect] | |
− | + | apply_to=attack | |
− | + | # [filter] | |
− | + | range=ranged | |
− | + | # [/filter] | |
− | + | increase_damage=2 | |
− | + | [/effect] | |
− | + | [/object] | |
− | |||
− | |||
− | |||
− | [/ | ||
− | [/ | ||
[/command] | [/command] | ||
[/option] | [/option] | ||
Line 73: | Line 96: | ||
[option] | [option] | ||
message=_ "150 GP: Crystal Orb, damage +2 on magical attack" | message=_ "150 GP: Crystal Orb, damage +2 on magical attack" | ||
+ | [show_if] | ||
+ | {VARIABLE_CONDITIONAL gold greater_than 150} | ||
+ | [/show_if] | ||
[command] | [command] | ||
− | [ | + | [gold] |
− | + | amount=-150 | |
− | + | side=$side_number | |
− | + | [/gold] | |
− | + | [object] | |
− | + | silent = yes | |
− | + | [effect] | |
− | + | apply_to=attack | |
− | + | # [filter] | |
− | + | special=chance_to_hit | |
− | + | # [/filter] | |
− | + | increase_damage=2 | |
− | + | [/effect] | |
− | + | [/object] | |
− | |||
− | |||
− | [/ | ||
− | [/ | ||
[/command] | [/command] | ||
[/option] | [/option] | ||
[option] | [option] | ||
− | message=_ "250 GP: Toughness Increase Scroll, HP+10" | + | message=_ "250 GP: Toughness Increase Scroll, Max HP+10" |
+ | [show_if] | ||
+ | {VARIABLE_CONDITIONAL gold greater_than 250} | ||
+ | [/show_if] | ||
[command] | [command] | ||
− | [ | + | [gold] |
− | + | amount=-250 | |
− | + | side=$side_number | |
− | + | [/gold] | |
− | + | [object] | |
− | + | silent = yes | |
− | + | [effect] | |
− | + | apply_to=hitpoints | |
− | + | increase_total=10 | |
− | + | [/effect] | |
− | + | [/object] | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
[/command] | [/command] | ||
[/option] | [/option] | ||
Line 121: | Line 139: | ||
[option] | [option] | ||
message=_ "400 GP: Seven-League Boots, gives MP of 10" | message=_ "400 GP: Seven-League Boots, gives MP of 10" | ||
+ | [show_if] | ||
+ | {VARIABLE_CONDITIONAL gold greater_than 400} | ||
+ | [/show_if] | ||
[command] | [command] | ||
− | [ | + | [gold] |
− | + | amount=-400 | |
− | + | side=$side_number | |
− | + | [/gold] | |
− | + | [object] | |
− | + | silent = yes | |
− | + | [effect] | |
− | + | apply_to=movement | |
− | + | set=10 | |
− | + | [/effect] | |
− | + | [/object] | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
[/command] | [/command] | ||
[/option] | [/option] | ||
Line 145: | Line 159: | ||
[option] | [option] | ||
message=_ "400 GP: Boot Upgrade, MP+1" | message=_ "400 GP: Boot Upgrade, MP+1" | ||
+ | [show_if] | ||
+ | {VARIABLE_CONDITIONAL gold greater_than 400} | ||
+ | [/show_if] | ||
[command] | [command] | ||
− | [ | + | [gold] |
− | + | amount=-400 | |
− | + | side=1 | |
− | + | [/gold] | |
− | + | [object] | |
− | + | silent = yes | |
− | + | [effect] | |
− | + | apply_to=movement | |
− | + | increase=1 | |
− | + | [/effect] | |
− | + | [/object] | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
[/command] | [/command] | ||
[/option] | [/option] | ||
Line 169: | Line 179: | ||
[option] | [option] | ||
message=_ "All GP: Healing Fountain, HP:+50" | message=_ "All GP: Healing Fountain, HP:+50" | ||
+ | [show_if] | ||
+ | {VARIABLE_CONDITIONAL gold greater_than 0} | ||
+ | [/show_if] | ||
[command] | [command] | ||
− | [ | + | [gold] |
− | + | amount=-$css_gold | |
− | + | side=$side_number | |
− | + | [/gold] | |
− | + | [object] | |
− | + | silent = yes | |
− | + | [effect] | |
− | + | apply_to=hitpoints | |
− | + | increase=50 | |
− | + | violate_max=1 | |
− | + | [/effect] | |
− | + | [/object] | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
[/command] | [/command] | ||
[/option] | [/option] | ||
Line 194: | Line 200: | ||
[option] | [option] | ||
message=_ "300 GP: Rage Stone, add a melee swing" | message=_ "300 GP: Rage Stone, add a melee swing" | ||
+ | [show_if] | ||
+ | {VARIABLE_CONDITIONAL gold greater_than 300} | ||
+ | [/show_if] | ||
[command] | [command] | ||
− | [ | + | [gold] |
− | + | amount=-300 | |
− | + | side=$side_number | |
− | + | [/gold] | |
− | + | [object] | |
− | + | silent = yes | |
− | + | [effect] | |
− | + | apply_to=attack | |
− | + | # [filter] | |
− | + | range=melee | |
− | + | # [/filter] | |
− | + | increase_attacks=1 | |
− | + | [/effect] | |
− | + | [/object] | |
− | |||
− | |||
− | |||
− | [/ | ||
− | [/ | ||
[/command] | [/command] | ||
[/option] | [/option] | ||
Line 219: | Line 223: | ||
[option] | [option] | ||
message=_ "350 GP: Sight Stone, add a ranged attack" | message=_ "350 GP: Sight Stone, add a ranged attack" | ||
+ | [show_if] | ||
+ | {VARIABLE_CONDITIONAL gold greater_than 350} | ||
+ | [/show_if] | ||
[command] | [command] | ||
− | [ | + | [gold] |
− | + | amount=-350 | |
− | + | side=$side_number | |
− | + | [/gold] | |
− | + | [object] | |
− | + | silent = yes | |
− | + | [effect] | |
− | + | apply_to=attack | |
− | + | # [filter] | |
− | + | range=ranged | |
− | + | # [/filter] | |
− | + | increase_attacks=1 | |
− | + | [/effect] | |
− | + | [/object] | |
− | |||
− | |||
− | |||
− | [/ | ||
− | [/ | ||
[/command] | [/command] | ||
[/option] | [/option] | ||
Line 244: | Line 246: | ||
[option] | [option] | ||
message=_ "350 GP: Fire Scepter, adds 8-1 ranged magical fire" | message=_ "350 GP: Fire Scepter, adds 8-1 ranged magical fire" | ||
+ | [show_if] | ||
+ | {VARIABLE_CONDITIONAL gold greater_than 350} | ||
+ | [/show_if] | ||
[command] | [command] | ||
− | [ | + | [gold] |
− | + | amount=-350 | |
− | + | side=$side_number | |
− | + | [/gold] | |
− | + | [object] | |
− | + | silent = yes | |
− | + | [effect] | |
− | + | apply_to=new_attack | |
− | + | name=Fire Scepter | |
− | + | type=fire | |
− | + | range=ranged | |
− | + | [specials] | |
− | + | {WEAPON_SPECIAL_MAGICAL} | |
− | + | [/specials] | |
− | + | damage=8 | |
− | + | number=1 | |
− | + | [/effect] | |
− | + | [/object] | |
− | |||
− | |||
− | |||
− | |||
[/command] | [/command] | ||
[/option] | [/option] | ||
Line 272: | Line 273: | ||
[option] | [option] | ||
message=_ "350GP: Ice Scepter, adds 8-1 ranged magical ice" | message=_ "350GP: Ice Scepter, adds 8-1 ranged magical ice" | ||
+ | [show_if] | ||
+ | {VARIABLE_CONDITIONAL gold greater_than 350} | ||
+ | [/show_if] | ||
[command] | [command] | ||
− | [ | + | [gold] |
− | + | amount=-350 | |
− | + | side=$side_number | |
− | + | [/gold] | |
− | + | [object] | |
− | + | silent = yes | |
− | + | [effect] | |
− | + | apply_to=new_attack | |
− | + | name=Ice Scepter | |
− | + | type=cold | |
− | + | range=ranged | |
− | + | [specials] | |
− | + | {WEAPON_SPECIAL_MAGICAL} | |
− | + | [/specials] | |
− | + | damage=8 | |
− | + | number=1 | |
− | + | [/effect] | |
− | + | [/object] | |
− | |||
− | |||
− | |||
− | |||
[/command] | [/command] | ||
[/option] | [/option] | ||
[/message] | [/message] | ||
+ | {CLEAR_VARIABLE css_gold} | ||
[/event] | [/event] | ||
#enddef | #enddef | ||
+ | |||
+ | == Feature suggestions == | ||
+ | |||
+ | === Allow multiple choices in single dialog === | ||
+ | |||
+ | Instead of exiting after the player buys one item, a better shop allows the player to buy more than one. This can be done with an infinite loop, which exits when the player chooses the "exit" option. For example, the Colosseum's implementation: | ||
+ | |||
+ | [while] | ||
+ | [variable] | ||
+ | name=finished | ||
+ | boolean_equals=no | ||
+ | [/variable] | ||
+ | [do] | ||
+ | # ... | ||
+ | [option] | ||
+ | label= _ "Done" | ||
+ | [command] | ||
+ | {VARIABLE finished yes} | ||
+ | [/command] | ||
+ | [/option] | ||
+ | # ... | ||
+ | [/do] | ||
+ | [/while] | ||
+ | |||
+ | === Optionally enter the shop === | ||
+ | |||
+ | Instead of using ''moveto'' events, you can use [[InterfaceActionsWML#.5Bset_menu_item.5D|set_menu_item]] to allow the player to decide whether they want to enter the shop, by adding an "Enter Shop" option to the right-click menu. | ||
== See Also == | == See Also == |
Latest revision as of 22:05, 30 June 2019
Contents
A Shop Like Thing
In this page you can see different techniques of creating a shop.
Example implementations
There's a discussion thread that started in 2019 (Wesnoth 1.14).
The Colosseum add-on's shop
The add-on Colosseum has a shop that's intended to be usable by other add-ons. Basic usage is given in the readme file in the add-on.
Simple
Use this macro to place a moveto event in your scenario that defines a magic-items shop. Argument is a StandardLocationFilter.
Used macros:
- VARIABLE_CONDITIONAL (from file utils.cfg)
- CLEAR_VARIABLE (from file utils.cfg)
- WEAPON_SPECIAL_MAGICAL (from fileabilities.cfg)
#define CREATE_SIMPLE_SHOP FILTER [event] name=moveto first_time_only=no [filter] # this is not a macro. It is a argument token, # which will be substituted with argument value {FILTER} [/filter] [store_gold] side=$side_number variable=css_gold # it is bad idea to use simple variable names like "gold" inside macro # because you can overwrite values of variables, # which was defined outside of this macro and was supposed to be used for # anything else. To prevent any side effects, preceed macro-specific variables # with abbreviation of macro name [/store_gold] # this is easiest way to create menu in the game. # you just define each value and player sees them anytime he trigger this event [message] speaker=narrator message=_ "What items would you like to purchase?" image=wesnoth-icon.png [option] message=_ "140 GP: Sharpen Melee Weapon, damage:+2" [show_if] {VARIABLE_CONDITIONAL gold greater_than 140} [/show_if] [command] [gold] amount=-140 side=$side_number [/gold] [object] silent = yes [effect] apply_to=attack # You need to specify filter for your effect # but you should't use [filter] tags # [filter] range=melee # [/filter] increase_damage=2 [/effect] [/object] [/command] [/option] [option] message=_ "150 GP: Enchance Ranged Weapon, damage +2" [show_if] {VARIABLE_CONDITIONAL gold greater_than 150} [/show_if] [command] [gold] side=$side_number amount=-150 [/gold] [object] silent = yes [effect] apply_to=attack # [filter] range=ranged # [/filter] increase_damage=2 [/effect] [/object] [/command] [/option] [option] message=_ "150 GP: Crystal Orb, damage +2 on magical attack" [show_if] {VARIABLE_CONDITIONAL gold greater_than 150} [/show_if] [command] [gold] amount=-150 side=$side_number [/gold] [object] silent = yes [effect] apply_to=attack # [filter] special=chance_to_hit # [/filter] increase_damage=2 [/effect] [/object] [/command] [/option] [option] message=_ "250 GP: Toughness Increase Scroll, Max HP+10" [show_if] {VARIABLE_CONDITIONAL gold greater_than 250} [/show_if] [command] [gold] amount=-250 side=$side_number [/gold] [object] silent = yes [effect] apply_to=hitpoints increase_total=10 [/effect] [/object] [/command] [/option] [option] message=_ "400 GP: Seven-League Boots, gives MP of 10" [show_if] {VARIABLE_CONDITIONAL gold greater_than 400} [/show_if] [command] [gold] amount=-400 side=$side_number [/gold] [object] silent = yes [effect] apply_to=movement set=10 [/effect] [/object] [/command] [/option] [option] message=_ "400 GP: Boot Upgrade, MP+1" [show_if] {VARIABLE_CONDITIONAL gold greater_than 400} [/show_if] [command] [gold] amount=-400 side=1 [/gold] [object] silent = yes [effect] apply_to=movement increase=1 [/effect] [/object] [/command] [/option] [option] message=_ "All GP: Healing Fountain, HP:+50" [show_if] {VARIABLE_CONDITIONAL gold greater_than 0} [/show_if] [command] [gold] amount=-$css_gold side=$side_number [/gold] [object] silent = yes [effect] apply_to=hitpoints increase=50 violate_max=1 [/effect] [/object] [/command] [/option] [option] message=_ "300 GP: Rage Stone, add a melee swing" [show_if] {VARIABLE_CONDITIONAL gold greater_than 300} [/show_if] [command] [gold] amount=-300 side=$side_number [/gold] [object] silent = yes [effect] apply_to=attack # [filter] range=melee # [/filter] increase_attacks=1 [/effect] [/object] [/command] [/option] [option] message=_ "350 GP: Sight Stone, add a ranged attack" [show_if] {VARIABLE_CONDITIONAL gold greater_than 350} [/show_if] [command] [gold] amount=-350 side=$side_number [/gold] [object] silent = yes [effect] apply_to=attack # [filter] range=ranged # [/filter] increase_attacks=1 [/effect] [/object] [/command] [/option] [option] message=_ "350 GP: Fire Scepter, adds 8-1 ranged magical fire" [show_if] {VARIABLE_CONDITIONAL gold greater_than 350} [/show_if] [command] [gold] amount=-350 side=$side_number [/gold] [object] silent = yes [effect] apply_to=new_attack name=Fire Scepter type=fire range=ranged [specials] {WEAPON_SPECIAL_MAGICAL} [/specials] damage=8 number=1 [/effect] [/object] [/command] [/option] [option] message=_ "350GP: Ice Scepter, adds 8-1 ranged magical ice" [show_if] {VARIABLE_CONDITIONAL gold greater_than 350} [/show_if] [command] [gold] amount=-350 side=$side_number [/gold] [object] silent = yes [effect] apply_to=new_attack name=Ice Scepter type=cold range=ranged [specials] {WEAPON_SPECIAL_MAGICAL} [/specials] damage=8 number=1 [/effect] [/object] [/command] [/option] [/message] {CLEAR_VARIABLE css_gold} [/event] #enddef
Feature suggestions
Allow multiple choices in single dialog
Instead of exiting after the player buys one item, a better shop allows the player to buy more than one. This can be done with an infinite loop, which exits when the player chooses the "exit" option. For example, the Colosseum's implementation:
[while] [variable] name=finished boolean_equals=no [/variable] [do] # ... [option] label= _ "Done" [command] {VARIABLE finished yes} [/command] [/option] # ... [/do] [/while]
Optionally enter the shop
Instead of using moveto events, you can use set_menu_item to allow the player to decide whether they want to enter the shop, by adding an "Enter Shop" option to the right-click menu.