From 87df8a3233e710898c64ce63f78f41ac6f40c73b Mon Sep 17 00:00:00 2001 From: Cekis Date: Wed, 2 Feb 2022 22:03:54 -0800 Subject: [PATCH] Updated How To Create a Custom Vendor (markdown) --- How-To-Create-a-Custom-Vendor.md | 534 ++++++++++++++++++++++++------- 1 file changed, 416 insertions(+), 118 deletions(-) diff --git a/How-To-Create-a-Custom-Vendor.md b/How-To-Create-a-Custom-Vendor.md index dd50a00..138857b 100644 --- a/How-To-Create-a-Custom-Vendor.md +++ b/How-To-Create-a-Custom-Vendor.md @@ -1,195 +1,493 @@ **_(submitted by HeronOfAlexandria)_** -# Overview +# Revision + +Version 1.0 of the Guide to Creating Vendors. + +# Introduction + +This guide provides instructions for creating and stocking server vendors. These +instructions include the templates, strings, and tables containing the stock, +payment methods, and making an event to turn the vendors on and off. + +In this example, we will be creating three vendors and a gift box, the latter +being a generic container that can hold simple items. The first vendor will sell +boxes of marauder tokens for cash, the second sells chronicler tokens in +exchange for marauder tokens, and the third sells heroic tokens in exchange for +chronicler tokens. This approach intends to demonstrate the payment methods, +which will become clear as you read this guide. + +I provide a working example in my fork (HeronAlexandria · GitHub), and while I +have performed basic testing, I cannot guarantee that the example is bug-free. +Use my examples at your own risk, and remember, snapshot your VM before +beginning! + +You will need Sitners, but we will not be building tre files. I will show you +how to place files in the client directory, so constructing a tre file is +unnecessary, making development much easier. Programming is required, but it is +all in Java, and for the most part, you will be able to use what others have +written and make some simple changes. + +There are two commits for this guide. The first is [Vendor Demonstration · +HeronAlexandria/dsrc@aa06fbf · +GitHub](https://github.com/HeronAlexandria/dsrc/commit/aa06fbf460ea5c3b0963f4699ede6e1079552335), +which contains the code for the vendors and the gift box. The second is [Fixes +to vendor demo. Added event to turn vendors on and off · +HeronAlexandria/dsrc@3e99932 · +GitHub](https://github.com/HeronAlexandria/dsrc/commit/3e999320bf4036494d1b2d9836c0e46d50fa11ee), +which contains some minor fixes and changes to allow the vendors to be turned on +and off in server configuration. + +# The Generic Gift Box + +The vendors only sell one item at a time. For example, during a holiday event, +you earn tokens, and you trade those tokens in for a reward. You get a single +item from the vendor. Some things sold on vendors might be a small stack, but +that is one item with charges, and the object was defined that way. The generic +gift box allows the creation of multiple items without changing the time or +providing additional definitions. + +A functioning gift box requires a script, an entry in the master items table, a +string file for the box, and an entry in the static items table. Since we added +an object, we will copy the CRC file from the server to the client. This is a +lot to take in, so let’s go through it. + +To make a gift box, you add an item to the master items table, attach the +script, and set the object variables. After compiling, you move the crc file +from the server to the client. To see strings for the responses from the box and +an actual name, you must change string files; we will go over that soon. When +the object gets created, the object variables are assigned to the object, and +the script is attached. + +The box will not work without the script, so let’s begin there. I have already +written the script, which you can find at +[dsrc/sku.0/sys.server/compiled/game/script/item/gift_boxes at master · +HeronAlexandria/dsrc · +GitHub](https://github.com/HeronAlexandria/dsrc/tree/master/sku.0/sys.server/compiled/game/script/item/gift_boxes). +The name of the script is generic_gift_box.java. + +The gift box is modeled after the standard uniform box +(item_npe_uniform_crate_01_01). The model script is npe.uniform_crate. The +uniform box has a simple menu, including an open action. When opened, items are +created and placed in the character’s inventory, and the box is destroyed. The +gift box works the same way, except that the contents are programmable. + +The script expects strings to be stored in a file named generic_gift_box.stf. I +created this file with Sitners and placed it in the client folder in string/en. +While we are on this subject, let’s take a quick look at where to store +client-side resources. You are probably familiar with tre files, but you do not +have to store assets in tre files; you can place them directly in the client +folder if you follow the file structure. Below is a partial screenshot of my +client folder. Any assets in this structure override tre files, so if you place +an asset in a tree file and it is not working, check the folder structure for a +copy of the file. + + +![](https://i.imgur.com/CeyxWuc.png) + + +The string file for the box is expected to be stored in the English string +folder, as shown below. I have placed this file in my client assets folder in my +fork; you can download it from there. + +![](https://i.imgur.com/IlKNBSH.png) + +The script adds the menu to take the string from the string file; you can see +this in OnObjectMenuRequest. When the box is used, OnObjectMenuSelect is called. +This method parses the object variables and checks for validity, and if the +variables are valid, the items are created, and the box is destroyed. + +Take a look at the master items table located in +[dsrc/sku.0/sys.server/compiled/game/datatables/item/master_item at master · +HeronAlexandria/dsrc +(github.com)](https://github.com/HeronAlexandria/dsrc/tree/master/sku.0/sys.server/compiled/game/datatables/item/master_item). +Find the entry for the item item_heron_gift_pgc_01_10. Note that this is +assigned the generic uniform template (column B), has some object variables +(column G), which we will discuss in a moment, and assigns the generic gift box +script (column K) to the object. + +When the object is created, the object variables and script are assigned. Note +that you can edit the script, then reload the script, and you do not have to +update the object. If you edit the object variables, recompile the master items +table and reload the data table, this does not update any object variables for +existing objects. You would have to destroy any existing items and recreate them +or edit the object variables manually. + +The provided script recognizes four object variables: mode, source, selections, +and items, and they are case sensitive. Mode, source, and selections have +defaults, but items must be defined. Mode is either “all” or “random” and +defaults to “all.” When mode is set to “all,” everything in the items list is +generated; when the value of selections defines “random”, the number of items +generated, selections are ignored if the mode is “all” and must be at least one +when the mode is “random.” + +The value of source is either “list” or “table” and defaults to “list.” When the +value is “list,” the items are in a semi-colon delimited list. Take a look a the +object variables for item_heron_gift_pgc_01_10 for an example. Note the colon +after each entry; this tells the script to create 10 of the item. The script +will create ten copper, silver, and gold chronicler tokens in this example. Note +that mode is not defined, so it defaults to all. + +If the source is “table,” items refer to a table. Placing items in a table +allows them to be restricted by class if desired. Refer to the object +item_heron_gift_test in the master item table for an example. For the most part, +a list will do what you need. + +The procedure for creating a new gift box is simple. Copy one of the entries I +have made in the master items table, change the template in column B if you +like, and then change the object variables. Edit the table “static_item_n.sft” +located in the client directory string/en using Sitners and add your object name +and string description. The following screenshot shows the location of the +master items table: -This document provides instructions for creating vendors, assigning an -appearance, name, and title to the vendor, stocking the vendor, spawning the -vendor, and setting a flag to turn the vendor on and off. It also covers -different types of payment, such as credits and tokens. +![](https://i.imgur.com/3OPGz8b.png) + + +I placed my static items string file in [client-assets/string/en at master · +HeronAlexandria/client-assets +(github.com)](https://github.com/HeronAlexandria/client-assets/tree/master/string/en), +named “heron_static_item_n.stf”for reference. + +Recompile, start your server, and try creating the object you defined using the +createstaticitem command. You should be able to open the box and claim your +goodies. -The procedure for creating a vendor is to create the NPC, place the NPC, and -then provide a table of items for the vendor to sell. +# Creating the First Vendor -For this example, we will be creating a vendor that provides Mandalorian armor -schematics in exchange for Marauder tokens and credits. +The first vendor will offer a gift box containing marauder tokens for credits. +These tokens will be used to pay the second vendor, who will sell chronicler +tokens, and the third vendor will accept the chronicler tokens and sell heroic +tokens. Creating a vendor is not difficult, but there are a lot of steps, and it +is easy to make a mistake. -# What You Need +To create a vendor, we perform the following steps: -This is not complicated, but it does have a lot of steps. You will need to -understand how to get code from the source repository from GIT, and you will -need to install Sitners (SIE). I used version 3.709.95. I downloaded the source -code in a zip file, unzipped the files, then created the files I needed and -uploaded them to my VM, as the Windows tools are easier to use. +1. Create the templates for the NPC. -I used NotePad++ as my text editor and SIE to create and edit string and tre -files. You will need some familiarity with SIE. If this is your first-time using -SIE, you will figure it out. We will be using files from the DSRC, Server Data, -and Client Data repositories. +2. Create a conversation script for the NPC. -# Creating the NPC +3. Create the inventory. -The easiest way to create the NPC is to begin with a related NPC, copy the -necessary files, and modify to suit our needs. We are going to use the TCG -vendor for a template; you will find the template in -“`dsrc\\sku.0\\sys.shared\\compiled\\game\\object\\mobile`”. The filename is -“`shared_vendor_tcg_1.tpf`” +4. Add the entry to the creature’s table. -Copy this file and rename it to “`shared_vendor_tutorial.tpf`”. This is a text -file, so we can edit it with a text editor; do so now, and take note of the -screenshot below: +5. Add the spawner to the proper build-out file. -![](https://imgur.com/mYerDhc.png) +6. Recompile and copy the files. -We are going to change lines 6 and 9. The objectName entry on line six refers to -location of the string table and the key in the string table. This tells the -client what string to display for the vendor. The entry tells the client to look -in the string table “creature_names.stf” which is located in the mob directory -and use the key “vendor_tcg_1”to find the string to display for the vendor. You -will find this string table in the client assets repository (I used the client -assets master branch), in the directory “string/mob.” +## Creating the Templates -Below is a screenshot from SIE showing the key and the string value in the -creature_names.stf file. This is the name the client will display for the -vendor. +The first vendor is the marauder token vendor, which I named vendor_tok_m. There +are thus two template files to create: vendor_tok_m.tpf and +shared_vendor_tok_m.tpf. The first file, vendor_tok_m.tpf is located in +dsrc/sku.0/sys.server/compiled/game/object/mobile. I based this on +vendor_tcg_1.tpf; I copied the file and made the changes. You can use mine for a +template or copy another. The only information that you need to change is the +location of the shared template, as shown below: -![](https://imgur.com/Du44cOI.png) +![](https://i.imgur.com/MrSr8DY.png) -We are not going to edit this file; it is best that if you put your extensions -in their own file to avoid future merge errors. We use SIE to create a new -string table. We create the following entry, and save the file as -“`vendor_tutorial.stf`” -![](https://imgur.com/coR2zyx.png) +The reference to the shared template is the compiled file, which is named +shared_vendor_tok_m.iff, not shared_vendor_tok_m.tpf. Remember that file names +in the Linux world are case-sensitive. -Save the file somewhere that is easy to find; we will need it later when we -construct our tre file. Now change line six to match, like so: +The shared template file is located in +dsrc/sku.0/sys.shared/compiled/game/object/mobile. Below is a screenshot of +shared_vendor_tok_m.tpf: -![](https://imgur.com/ghyRmNi.png) +![](https://i.imgur.com/p3J9Ibs.png) -Line 9 is used to define the appearance. The appearance files are in the -“appearance” folder in the server data. We are going to leave this as it is; you -can experiment on your own and look at existing files to determine the values to -set. -# Pending +Take careful note of the objectName. This entry defines the name of the NPC in +the string file and the name of the string file to look in. I tried using a file +other than creature_names, but it would not work. This string file is built on +the client and copied to the server. Without the string file, the server will +randomly generate a name for the NPC. I have added my string file to +[client-assets/string/en/mob at master · HeronAlexandria/client-assets +(github.com)](https://github.com/HeronAlexandria/client-assets/tree/master/string/en/mob), +named heron_creature_names.stf for reference. Here is a screenshot and that +shows the names of the NPCs and their string names: -events.java, buildout, event controller, template +![](https://i.imgur.com/NBoMsRr.png) -# Assets -`shared_vendor_tok_x.tpf` +## Create the Conversation Script -`shared_vendor_tok_m.tpf` +The conversation scripts for vendors are straightforward. I used a TCG vendor +for the base, but you can use my token_m_vendor.java script. You will find the +conversation script at [dsrc/token_m_vendor.java at master · +HeronAlexandria/dsrc +(github.com)](https://github.com/HeronAlexandria/dsrc/blob/master/sku.0/sys.server/compiled/game/script/conversation/token_m_vendor.java). -`shared_vendor_tok_c.tpf` +You need to change the reference to the conversation file on line 14 and change +everything named token_m_vendor to your vendor’s name. These references include +the method names, such as token_m_vendor_condition__defaultCondition on line 14 +and the strings on line 30. Just use the find function of an editor to move +through the file and change the references. The string file referenced on line +14 goes in the client folder as shown below: -`game/object/mobile` +![](https://i.imgur.com/JMiBznO.png) -Template (server mobile): +I created these from a TCG vendor conversation, but you are welcome to use mine +and edit them as you wish. These files are included at +[client-assets/string/en/conversation at master · HeronAlexandria/client-assets +(github.com)](https://github.com/HeronAlexandria/client-assets/tree/master/string/en/conversation). -`vendor_tcg_1.tpf to vendor_tok_x.tpf` +I have different conversation files for my three vendors, but they are simple +enough to share the same conversation script and string files. Just copy files, +change the names, and make the changes you need. -`vendor_tcg_1.tpf to vendor_tok_m.tpf` +## Create Inventory -`vendor_tcg_1.tpf to vendor_tok_c.tpf` +The vendor’s inventory is stored in a data table. There are two steps for the +vendor’s inventory; the first is to create the gift box, and the second is to +add it to the vendor’s data table. Refer to the master item table I provided and +look for item_heron_gift_marauder_01_50. Take a look at the attached script and +the object variables. The object variables instruct the script to create +marauder tokens when the box is opened. -Server: -`datatables/mob/creatures.tab` +Now go look at the vendor’s data table token_m_vendor.tab, which you will find +in [dsrc/sku.0/sys.server/compiled/game/datatables/item/vendor at master · +HeronAlexandria/dsrc +(github.com)](https://github.com/HeronAlexandria/dsrc/tree/master/sku.0/sys.server/compiled/game/datatables/item/vendor). +Here is a screenshot from my VM: -`creatures.tab` set the token type -`datatables/item/vendor` +![](https://i.imgur.com/g3r7TWh.png) -`token_x_vendor.tab` +![](https://i.imgur.com/XNiojCi.png) -`token_m_vendor.tab` -`token_c_vendor.tab` +This vendor only sells the marauder token box I defined in the master items +table for ten credits. -Conversations: +## Add the Vendor to the Creature’s Table -`script/conversation` +The creature’s table, creatures.tab, is located in +dsrc/sku.0/sys.server/compiled/game/datatables/mob; refer to +[dsrc/sku.0/sys.server/compiled/game/datatables/mob at master · +HeronAlexandria/dsrc +(github.com)](https://github.com/HeronAlexandria/dsrc/tree/master/sku.0/sys.server/compiled/game/datatables/mob) +for mine. -`token_x_vendor.java` +There are many entries, so the easiest way to look at the vendor definition is +to look at my table. Find “vendor_tok_m.tab” Use this as a guide when making +your own. In general, you want to copy my entry, change the name in column A +then make changes to columns N (the NPC template), BM (sets the object +variables), BN (attaches the scripts). -`token_m_vendor.java` +The NPC template is the compiled template you defined above. The object +variables set the table name from which the vendor’s inventory is taken. The +scripts in column BN are the vendor script npc.vendor.vendor, which provides the +vendor functionality, and the conversation script we created earlier. -`token_c_vendor.java` +The creature’s table entry binds the NPC template, vendor table, and the scripts +together. -String file +## Add Spawner -`conversation/token_x_vendor` +Now that we have the definitions done, we need to add the spawner so the NPC +will spawn. The NPC is created with an area spawner, but you must know which +build-out file to place the spawner in, the coordinates, and the facing. +Buildout coordiantes are not the same as world coordiantes. Fortunately, Aconite +has provided a utility for doing just that: -`conversation/token_m_vendor` -`conversation/token_c_vendor` +![](https://i.imgur.com/zU6dR8K.png) -Build out file +![](https://i.imgur.com/7FtxcRr.png) -Do not forget the shared file +The original link is found here: +. -`dsrc\\sku.0\\sys.server\\compiled\\game\\datatables\\buildout\\tatooine\\tatooine_6_2.tab` +Use the above script to get the build-out coordinates, the quaternion (facing), +and the build-out file. You will place the spawner in the build-out file. Take a +look at [dsrc/sku.0/sys.server/compiled/game/datatables/buildout/tatooine at +master · HeronAlexandria/dsrc +(github.com)](https://github.com/HeronAlexandria/dsrc/tree/master/sku.0/sys.server/compiled/game/datatables/buildout/tatooine), +and find the file vendor_demo_mos_eisley.tab. I placed the definitions for my +vendors in that file. If you treat this guide as a tutorial, the spawners go in +tatooine_6_2.tab. The file vendor_demo_mos_eisley.tab is a separate build-out +file used to turn the vendors on and off. I will cover that topic last. If you +plan to make your vendors switchable, I suggest getting them working and then +adding the configuration last. -Copy the string file to the server +Please take a look at the build-out file I provided and use it as a guide for +making your spawners. -Copy the crc file to the client +## Recompile and Copy Files -## To Do +Now recompile. Check the crc files. They are located in +swg-main/data/sku.0/sys.client/build/game/misc, +swg-main/data/sku.0/sys.server/build/game/misc, and +swg-main/data/sku.0/serverdata/misc. The files locate din client and +serverdata/misc are the same file. If the crc did not rebuild, then run run ant +build_object_template_crc to force a crc rebuild. -Object vars: +Copy the client crc file to the client directory as shown below: -`string:item.vendor.vendor_table=token_x_vendor,int:ai.noClap=1` +![](https://i.imgur.com/fxNkbGe.png) -in +If you do not copy the crc file, the client will not find the vendor, and it +will not spawn correctly. -`dsrc\\sku.0\\sys.server\\compiled\\game\\datatables\\item\\vendor` +Next, copy the shared vendor templates from the server to the client. You will +find them on the server here: -scripts: +![](https://i.imgur.com/GQM9Aur.png) -`npc.vendor.vendor,conversation.token_x_vendor` +They go in the client folder here: -`npc.vendor.vendor,conversation.tcg_vendor` +![](https://i.imgur.com/IlKNBSH.png) -the script is tcg_vendor.java located in -`dsrc\\sku.0\\sys.server\\compiled\\game\\script\\conversation\\tcg_vendor.java` -Set VENDOR_TOKEN_TYPE ("`item.token.type`") otherwise it uses heroic tokens +Remember, any files in the client folder override any entries in tre files. We +could put the shared vendor files in a tre file without fear of being overridden +since they do not exist, but it is easier to develop without making tre files. -# The Box +Finally, we want to copy the creature names string file from the client to the +server. If you do not do this, the random name generator will generate a name +for your vendor. The file is named creature_names.stf and is located in the +client folder here: -Open, Examine, Destroy -# Hiding Vendors +![](https://i.imgur.com/s00HScf.png) -`dsrc\\sku.0\\sys.server\\compiled\\game\\script\\event\\holiday_controller.java` -`dsrc\\sku.0\\sys.server\\compiled\\game\\script\\event\\planet_event_handler.java` +The file goes on the server, as shown below. Note that we only need the English +string file. -Shared Area file -# Broken Things +![](https://i.imgur.com/38KFTHA.png) -Slave I ITV -Bestine Election +## You are Done! -# Check This +Once the above steps are completed, start your server and test your vendor. If +you did everything correctly, it would work just fine. If not, go back through +the steps one at a time, or ask for help on Discord. -`item_reimbursement_list` +# Creating the Second Vendor -![](https://imgur.com/X0NcmVD.png) +The second vendor will offer chronicler tokens in exchange for marauder tokens. +Repeat the steps for the first vendor; remember that the vendor’s name is +vendor_tok_c. Note that in the creature’s table, the object variable defines a +token type, which means that token0 in the vendor table refers to the marauder +token, and the others are unused. Even though the other tokens were not used, I +had to define through token4 to avoid an index exception. -![](https://imgur.com/OnwrNCK.png) +Refer to the files I provided in my fork as examples, using the steps to create +the first vendor as a guide. -@Contributors Upon request I've pushed a prototype of my buildout utility -script. It is a work in progress, but serves its simple purpose at this time. To -use, attach `developer.buildout_utility` to your player, spawn an object where you -want it all pretty with whatever rotation and whatever, and then target it and -say in spatial getBuildoutInfo and you'll get an SUI window with everything that -you need to put in a buildout data table for an object to spawn correctly. Feel -free to report any bugs to me. This is currently for exteriors only, but as -Elour will tell you, use a dungeon_spawner for an interior anyways. +# Creating the Third Vendor -`object/tangible/npe/npe_generic_uniform_box.iff` +The third vendor sells heroic tokens in exchange for chronicler tokens. You will +notice that I did not define boxes for the echo base tokens; I leave that as an +exercise for the reader. This vendor takes only tokens, not cash. The default +types are used since we did not define a token type. The default tokens are +defined in the file trail.java located in +dsrc/sku.0/sys.server/compiled/game/script. The default types are defined in the +array HEROIC_TOKENS. Thus, token0 is Axkva Min, token1 is Tusken, and so on. -`item_heron_gift_axkva_01_05` +Refer to the files I provided in my fork as examples, using the steps to create +the first vendor as a guide. + +# Toggling Vendors + +To toggle vendors on and off, like the holiday vendors, you have to place the +spawners in a standalone build-out file, add that build-out file to the planet’s +areas, and then bind that area to an event. You then update the holiday +controller to start and stop the event. Once this is done, you can turn the +vendors on and off in local options. It is not that complicated, but we will go +through the steps briefly. + +Note that you should implement this functionality when you need to turn vendors +on and off. Remove the spawners if you want to remove vendors and never see +them, such as the TCG vendors. This approach really should only be used for +events, such as Halloween, Lifeday, or your server anniversary event. + +1. Define the build-out file. + +2. Add the build-out file to the areas. + +3. Update the holiday controller. + +4. Rebuild and copy the area file + +5. Turn the event on or off in local options. + +## Define Build-Out + +Remember when we defined the vendor spawners and ignored the +vendor_demo_mos_eisley.tab file and placed the spawners in tatooine_6_2.tab? Now +you know why the spawners for my vendors are in a separate file. Take the +spawners out of tatooine_6_2.tab, and put them in vendor_demo_mos_eisley.tab. +You can find the build-out files in +dsrc/sku.0/sys.server/compiled/game/datatables/buildout/tatooine. + +## Add the Area + +The area file is shared (meaning it does on the client and server), which means +it is located in +dsrc/sku.0/sys.server/compiled/game/datatables/buildout/Tatooine. The area file +is named areas_tatooine.tab. Here is a screenshot of the relevant area: + + +![](https://i.imgur.com/SahnGpm.png) + + +I set the area for the vendor demo to be the same as the Halloween area. Note +column Y, which sets the name of the event. This means that “vendor_demo_event” +must be running for this area to be active. + +## Update Holiday Controller + +We need to update the holiday controller to create the vendor demo event. You +will find the holiday controller in +dsrc/sku.0/sys.server/compiled/game/script/event, named +holliday_controller.java. The link to my fork is +[dsrc/sku.0/sys.server/compiled/game/script/event at master · +HeronAlexandria/dsrc +(github.com)](https://github.com/HeronAlexandria/dsrc/tree/master/sku.0/sys.server/compiled/game/script/event). + +Look for the event I added, vendorDemoServer, and use it as a guide. There are a +few things that require an additional explanation. Take a look at the following +screenshot: + +![](https://i.imgur.com/jCVlN1r.png) + +See the messageTo calls on lines 20 and 29? Note the 120; this is the number of +seconds before the event starts. Vendors will not appear until the server runs +for two minutes. Note that the delays for the other events are much longer; I +set this demo to two minutes for easier testing. + +An example of checking to see if the event is running appears on line 47 in the +following screenshot: + +![](https://i.imgur.com/nz51275.png) + +Note that these checks do appear in more than one place; search the script for +them to get a clear picture. + +Finally, leave the OnHearSpeach method alone. In general, it does not work +correctly. You will turn your vendors on or off in a server restart, not talking +to the holiday controller. + +## Rebuild and Copy + +Now rebuild, and then find the area file and copy it to the client. In this +example, you will find the area file in the following location on the VM: + +![](https://i.imgur.com/WamPQvE.png) + +Copy that file to the following location on the client: + +![](https://i.imgur.com/Ed6hAEz.png) + + +## Turn on the Event + +To activate the event, add vendor_demo_event=1 or vendor_demo_event=true to your +localOptions.cfg, as you would any other event. The event will start when you +restart the server, and the vendors will respawn after the delay you specified +when you updated the holiday controller.