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