1 /* $Id$ */
2 /***************************************************************************
3  *                   (C) Copyright 2003-2011 - Stendhal                    *
4  ***************************************************************************
5  ***************************************************************************
6  *                                                                         *
7  *   This program is free software; you can redistribute it and/or modify  *
8  *   it under the terms of the GNU General Public License as published by  *
9  *   the Free Software Foundation; either version 2 of the License, or     *
10  *   (at your option) any later version.                                   *
11  *                                                                         *
12  ***************************************************************************/
13 package games.stendhal.server.entity.npc.behaviour.adder;
14 
15 import org.apache.log4j.Logger;
16 
17 import games.stendhal.common.constants.SoundID;
18 import games.stendhal.common.constants.SoundLayer;
19 import games.stendhal.common.grammar.Grammar;
20 import games.stendhal.common.grammar.ItemParserResult;
21 import games.stendhal.common.parser.Sentence;
22 import games.stendhal.server.core.engine.SingletonRepository;
23 import games.stendhal.server.entity.item.Item;
24 import games.stendhal.server.entity.item.StackableItem;
25 import games.stendhal.server.entity.npc.ChatAction;
26 import games.stendhal.server.entity.npc.ChatCondition;
27 import games.stendhal.server.entity.npc.ConversationPhrases;
28 import games.stendhal.server.entity.npc.ConversationStates;
29 import games.stendhal.server.entity.npc.EventRaiser;
30 import games.stendhal.server.entity.npc.SpeakerNPC;
31 import games.stendhal.server.entity.npc.action.BehaviourAction;
32 import games.stendhal.server.entity.npc.action.ComplainAboutSentenceErrorAction;
33 import games.stendhal.server.entity.npc.behaviour.impl.SellerBehaviour;
34 import games.stendhal.server.entity.npc.behaviour.journal.MerchantsRegister;
35 import games.stendhal.server.entity.npc.condition.AndCondition;
36 import games.stendhal.server.entity.npc.condition.NotCondition;
37 import games.stendhal.server.entity.npc.condition.SentenceHasErrorCondition;
38 import games.stendhal.server.entity.npc.fsm.Engine;
39 import games.stendhal.server.entity.player.Player;
40 import games.stendhal.server.events.SoundEvent;
41 
42 public class SellerAdder {
43 	private static Logger logger = Logger.getLogger(SellerAdder.class);
44 
45     private final MerchantsRegister merchantsRegister = SingletonRepository.getMerchantsRegister();
46 
47     /**
48 	 * Behaviour parse result in the current conversation.
49 	 * Remark: There is only one conversation between a player and the NPC at any time.
50 	 */
51 	private ItemParserResult currentBehavRes;
52 
addSeller(final SpeakerNPC npc, final SellerBehaviour behaviour)53 	public void addSeller(final SpeakerNPC npc, final SellerBehaviour behaviour) {
54 		addSeller(npc, behaviour, true);
55 	}
56 
addSeller(final SpeakerNPC npc, final SellerBehaviour sellerBehaviour, final boolean offer)57 	public void addSeller(final SpeakerNPC npc, final SellerBehaviour sellerBehaviour, final boolean offer) {
58 		final Engine engine = npc.getEngine();
59 
60 		merchantsRegister.add(npc, sellerBehaviour);
61 
62 		if (offer) {
63 			engine.add(
64 					ConversationStates.ATTENDING,
65 					ConversationPhrases.OFFER_MESSAGES,
66 					null,
67 					false,
68 					ConversationStates.ATTENDING, "I sell "
69 									+ Grammar.enumerateCollection(sellerBehaviour.dealtItems())
70 									+ ".", null);
71 		}
72 
73 		engine.add(ConversationStates.ATTENDING,
74 				ConversationPhrases.PURCHASE_MESSAGES,
75 				new SentenceHasErrorCondition(),
76 				false,
77 				ConversationStates.ATTENDING,
78 				null,
79 				new ComplainAboutSentenceErrorAction());
80 
81 		ChatCondition condition = new AndCondition(
82 			new NotCondition(new SentenceHasErrorCondition()),
83 			new NotCondition(sellerBehaviour.getTransactionCondition()));
84 
85 		engine.add(ConversationStates.ATTENDING,
86 				ConversationPhrases.PURCHASE_MESSAGES,
87 				condition,
88 				false,
89 				ConversationStates.ATTENDING,
90 				null,
91 				sellerBehaviour.getRejectedTransactionAction());
92 
93 		condition = new AndCondition(
94 			new NotCondition(new SentenceHasErrorCondition()),
95 			sellerBehaviour.getTransactionCondition());
96 
97 		engine.add(ConversationStates.ATTENDING,
98 				ConversationPhrases.PURCHASE_MESSAGES,
99 				condition,
100 				false,
101 				ConversationStates.ATTENDING,
102 				null,
103 				new BehaviourAction(sellerBehaviour, "buy", "sell") {
104 					@Override
105 					public void fireRequestOK(final ItemParserResult res, final Player player, final Sentence sentence, final EventRaiser raiser) {
106 						String chosenItemName = res.getChosenItemName();
107 
108 						// find out if the NPC sells this item, and if so,
109 						// how much it costs.
110 						if (res.getAmount() > 1000) {
111 							logger.warn("Refusing to sell very large amount of "
112 									+ res.getAmount()
113 									+ " " + chosenItemName
114 									+ " to player "
115 									+ player.getName() + " talking to "
116 									+ raiser.getName() + " saying "
117 									+ sentence);
118 							raiser.say("Sorry, the maximum number of "
119 									+ chosenItemName
120 									+ " which I can sell at once is 1000.");
121 						} else if (res.getAmount() > 0) {
122 							StringBuilder builder = new StringBuilder();
123 
124 							// When the user tries to buy several of a non-stackable
125 							// item, he is forced to buy only one.
126 							if (res.getAmount() != 1) {
127 								final Item item = sellerBehaviour.getAskedItem(chosenItemName);
128 
129 								if (item == null) {
130 									logger.error("Trying to sell a nonexistent item: " + chosenItemName);
131 								} else if (!(item instanceof StackableItem)) {
132 									builder.append("You can only buy one " + chosenItemName + " at a time. ");
133 									res.setAmount(1);
134 								}
135 							}
136 
137 							int price = sellerBehaviour.getUnitPrice(chosenItemName) * res.getAmount();
138 							if (player.isBadBoy()) {
139 								price = (int) (SellerBehaviour.BAD_BOY_BUYING_PENALTY * price);
140 
141 								builder.append("To friends I charge less, but you seem like you have played unfairly here. So,  ");
142 								builder.append(Grammar.quantityplnoun(res.getAmount(), chosenItemName, "a"));
143 							} else {
144 								builder.append(Grammar.quantityplnoun(res.getAmount(), chosenItemName, "A"));
145 							}
146 
147 							builder.append(" will cost ");
148 							builder.append(price);
149 							builder.append(". Do you want to buy ");
150 							builder.append(Grammar.itthem(res.getAmount()));
151 							builder.append("?");
152 
153 							raiser.say(builder.toString());
154 
155 							currentBehavRes = res;
156 							npc.setCurrentState(ConversationStates.BUY_PRICE_OFFERED); // success
157 						} else {
158 							raiser.say("Sorry, how many " + Grammar.plural(chosenItemName) + " do you want to buy?!");
159 						}
160 					}
161 				});
162 
163 		engine.add(ConversationStates.BUY_PRICE_OFFERED,
164 				ConversationPhrases.YES_MESSAGES,
165 				null,
166 				false,
167 				ConversationStates.ATTENDING,
168 				null,
169 				new ChatAction() {
170 					@Override
171 					public void fire(final Player player, final Sentence sentence, final EventRaiser raiser) {
172 						final String itemName = currentBehavRes.getChosenItemName();
173 						logger.debug("Selling a " + itemName + " to player " + player.getName());
174 
175 						boolean success = sellerBehaviour.transactAgreedDeal(currentBehavRes, raiser, player);
176 						if (success) {
177 							raiser.addEvent(new SoundEvent(SoundID.COMMERCE, SoundLayer.CREATURE_NOISE));
178 						}
179 
180 						currentBehavRes = null;
181 					}
182 				});
183 
184 		engine.add(ConversationStates.BUY_PRICE_OFFERED,
185 				ConversationPhrases.NO_MESSAGES,
186 				null,
187 				false,
188 				ConversationStates.ATTENDING,
189 				"Ok, how else may I help you?",
190 				null);
191 	}
192 }
193