Package games.stendhal.server.maps.quests

Source Code of games.stendhal.server.maps.quests.SadScientist

/* $Id: SadScientist.java,v 1.37 2011/05/18 20:20:33 kymara Exp $ */
/***************************************************************************
*                   (C) Copyright 2003-2010 - Stendhal                    *
***************************************************************************
***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************/
package games.stendhal.server.maps.quests;

import games.stendhal.common.grammar.Grammar;
import games.stendhal.common.parser.Sentence;
import games.stendhal.server.core.engine.SingletonRepository;
import games.stendhal.server.entity.item.Item;
import games.stendhal.server.entity.npc.ChatAction;
import games.stendhal.server.entity.npc.ChatCondition;
import games.stendhal.server.entity.npc.ConversationPhrases;
import games.stendhal.server.entity.npc.ConversationStates;
import games.stendhal.server.entity.npc.EventRaiser;
import games.stendhal.server.entity.npc.SpeakerNPC;
import games.stendhal.server.entity.npc.action.CollectRequestedItemsAction;
import games.stendhal.server.entity.npc.action.DropItemAction;
import games.stendhal.server.entity.npc.action.EquipItemAction;
import games.stendhal.server.entity.npc.action.IncreaseKarmaAction;
import games.stendhal.server.entity.npc.action.IncreaseXPAction;
import games.stendhal.server.entity.npc.action.MultipleActions;
import games.stendhal.server.entity.npc.action.SayRequiredItemsFromCollectionAction;
import games.stendhal.server.entity.npc.action.SayTextAction;
import games.stendhal.server.entity.npc.action.SayTimeRemainingAction;
import games.stendhal.server.entity.npc.action.SetQuestAction;
import games.stendhal.server.entity.npc.action.SetQuestAndModifyKarmaAction;
import games.stendhal.server.entity.npc.action.SetQuestToTimeStampAction;
import games.stendhal.server.entity.npc.action.StartRecordingKillsAction;
import games.stendhal.server.entity.npc.condition.AndCondition;
import games.stendhal.server.entity.npc.condition.GreetingMatchesNameCondition;
import games.stendhal.server.entity.npc.condition.KilledForQuestCondition;
import games.stendhal.server.entity.npc.condition.NotCondition;
import games.stendhal.server.entity.npc.condition.PlayerHasItemWithHimCondition;
import games.stendhal.server.entity.npc.condition.QuestActiveCondition;
import games.stendhal.server.entity.npc.condition.QuestCompletedCondition;
import games.stendhal.server.entity.npc.condition.QuestInStateCondition;
import games.stendhal.server.entity.npc.condition.QuestNotStartedCondition;
import games.stendhal.server.entity.npc.condition.QuestStateStartsWithCondition;
import games.stendhal.server.entity.npc.condition.TimePassedCondition;
import games.stendhal.server.entity.player.Player;
import games.stendhal.server.maps.Region;
import games.stendhal.server.util.ItemCollection;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;


/**
* QUEST: The Sad Scientist.
*
* PARTICIPANTS:
* <ul>
* <li>Vasi Elos, a scientist in Kalavan</li>
* <li>Mayor Sakhs, the mayor of semos</li>
* </ul>
*
* STEPS:
* <ul>
*     <li>Talk to Vasi Elos, a lonely scientist.</li>
*     <li>Give him all stuff he needs for a present for his honey.</li>
*     <li>Talk to semos mayor.</li>
*     <li>Bring Elos mayor's letter.</li>
*     <li>Kill the Imperial Scientist.</li>
*    <li>Give him the flask with his brother's blood.</li>
* </ul>
*
* REWARD:
* <ul>
*     <li>a pair of black legs</li>
*     <li>20 Karma</li>
*     <li>10000 XP</li>
* </ul>
*
* REPETITIONS:
* <ul>
*     <li>None</li>
* </ul>
*/
public class SadScientist extends AbstractQuest {

  private static Logger logger = Logger.getLogger(SadScientist.class);

  private static final String LETTER_DESCRIPTION = "You see a letter for Vasi Elos.";
  private static final String QUEST_SLOT = "sad_scientist";
  private static final int REQUIRED_MINUTES = 20;
  private static final String NEEDED_ITEMS = "emerald=1;obsidian=1;sapphire=1;carbuncle=2;gold bar=20;mithril bar=1";
 
  @Override
  public String getName() {
    return "TheSadScientist";
  }

  @Override
  public String getSlotName() {
    return QUEST_SLOT;
  }

  @Override
  public List<String> getHistory(final Player player) {
    final List<String> res = new ArrayList<String>();
    if (!player.hasQuest(QUEST_SLOT)) {
      return res;
    }
    final String questState = player.getQuest(QUEST_SLOT);
    // it might have been rejected before Vasi even explained what he wanted.
    if ("rejected".equals(questState)) {
      res.add("Vasi Elos asked me for help, but I'm not really interested to help the scientist.");
      return res;
    }
    res.add("Vasi Elos asked me bring gems, gold and mithril to make a present of jewelled legs for his honey, Vera.");
    if ((getConditionForBeingInCollectionPhase()).fire(player,null,null)) {
      final ItemCollection missingItems = new ItemCollection();
      missingItems.addFromQuestStateString(questState);
      res.add("The jewelled legs still need " + Grammar.enumerateCollection(missingItems.toStringList()) + ".");
      return res;
    }
    res.add("Vasi Elos needs a base to add those gems I brought, to. He asked for shadow legs.");
    if ("legs".equals(questState)) { 
      return res;
    }
    res.add("Vasi Elos is making jewelled legs with the gems I brought.");
    if (questState.startsWith("making")) { 
      return res;
   
    res.add("Vasi Elos asked me to speak to Mayor Sakhs to find out where Vera is.");
    if ("find_vera".equals(questState) && !player.isEquipped("note")) { 
      return res;
    }
    res.add("I have a note with some terrible news on it to give Vasi.");
    if ("find_vera".equals(questState) && player.isEquipped("note")) { 
      return res;
    }
    res.add("Vasi Elos is so sad and angry that Vera is gone. I must kill his own brother and give him a goblet of blood.");
    if (questState.startsWith("kill_scientist") && !new KilledForQuestCondition(QUEST_SLOT, 1).fire(player, null, null)) {
      return res;
    }
    res.add("I killed the Imperial Scientist Sergej Elos and must take the goblet of his blood as proof.");
    if (questState.startsWith("kill_scientist") && new KilledForQuestCondition(QUEST_SLOT, 1).fire(player, null, null)) {
      return res;
    }
    res.add("Vasi Elos is really sad. He's decorating the legs he made...with blood.");
    if (questState.startsWith("decorating")) { 
      return res;
    }
    res.add("The new legs, now black legs, darkened with blood and evil, are mine. " +
        "But at what cost?");
        if ("done".equals(questState)){
          return res;
    }
        // if things have gone wrong and the quest state didn't match any of the above, debug a bit:
    final List<String> debug = new ArrayList<String>();
    debug.add("Quest state is: " + questState);
    logger.error("History doesn't have a matching quest state for " + questState);
    return debug;
  }
 
  /* (non-Javadoc)
   * @see games.stendhal.server.maps.quests.AbstractQuest#addToWorld()
   */
  @Override
  public void addToWorld() {
    super.addToWorld();
    fillQuestInfo(
        "A Sad Scientist",
        "Vasi Elos, a lonely scientist, wants to deliver a present to his honey.",
        false);
    prepareQuestSteps();
  }

  private void prepareQuestSteps() {
    prepareScientist();
  }

  private void prepareScientist() {
    final SpeakerNPC scientistNpc = npcs.get("Vasi Elos");
    final SpeakerNPC mayorNpc = npcs.get("Mayor Sakhs");
    startOfQuest(scientistNpc);
    bringItemsPhase(scientistNpc);
    playerReturnsAfterRequestForLegs(scientistNpc);
    playerReturnsAfterGivingTooEarly(scientistNpc);
    playerReturnsAfterGivingWhenFinished(scientistNpc);
    playerReturnsWithoutLetter(scientistNpc);
    playerVisitsMayorSakhs(mayorNpc);
    playerReturnsWithLetter(scientistNpc);
    playerReturnsWithoutKillingTheImperialScientistOrWithoutGoblet(scientistNpc);
    playerReturnsAfterKillingTheImperialScientist(scientistNpc);
    playerReturnsToFetchReward(scientistNpc);
    playerReturnsAfterCompletingQuest(scientistNpc);
  }

  private void playerReturnsToFetchReward(SpeakerNPC npc) {
    // time has passed
    final ChatCondition condition = new AndCondition(new GreetingMatchesNameCondition(npc.getName()),
            new QuestStateStartsWithCondition(QUEST_SLOT,"decorating"),
            new TimePassedCondition(QUEST_SLOT, 1, 5)
          );
    final ChatAction action = new MultipleActions(
                      new SetQuestAction(QUEST_SLOT,"done"),
                      new IncreaseKarmaAction(20),
                      new IncreaseXPAction(10000),
                      // here, true = bind them to player
                      new EquipItemAction("black legs", 1, true)
                    );
    npc.add(ConversationStates.IDLE,
        ConversationPhrases.GREETING_MESSAGES,
        condition,
        ConversationStates.IDLE,
        "Here are the black legs. Now I beg you to wear them. The symbol of my pain is done. Fare thee well.",
        action);
   
    // time has not yet passed
    final ChatCondition notCondition = new AndCondition(new GreetingMatchesNameCondition(npc.getName()),
        new QuestStateStartsWithCondition(QUEST_SLOT,"decorating"),
        new NotCondition( new TimePassedCondition(QUEST_SLOT, 1, 5))
      );
    ChatAction reply = new SayTimeRemainingAction(QUEST_SLOT, 1, 5, "I did not finish decorating the legs. " +
            "Please check back in");
    npc.add(ConversationStates.IDLE,
        ConversationPhrases.GREETING_MESSAGES,
        notCondition,
        ConversationStates.IDLE,
        null,
        reply);
  }
 
  private void playerReturnsAfterKillingTheImperialScientist(SpeakerNPC npc) {
    final ChatCondition condition = new AndCondition(
        new QuestStateStartsWithCondition(QUEST_SLOT, "kill_scientist"),
        new KilledForQuestCondition(QUEST_SLOT, 1),
        new PlayerHasItemWithHimCondition("goblet")
      );
    ChatAction action = new MultipleActions(
                    new SetQuestAction(QUEST_SLOT, "decorating;"),
                    new SetQuestToTimeStampAction(QUEST_SLOT, 1),
                    new DropItemAction("goblet",1)
                    );
    npc.add(ConversationStates.IDLE, ConversationPhrases.GREETING_MESSAGES,
        new AndCondition(new GreetingMatchesNameCondition(npc.getName()), condition),
        ConversationStates.ATTENDING,
        "Ha, ha, ha! I will cover those jewelled legs with this blood and they will transform " +
        "into a #symbol of pain.",
        null);
   
    npc.add(ConversationStates.ATTENDING, "symbol",
        condition, ConversationStates.IDLE,
        "I am going to create a pair of black legs. Come back in 5 minutes.",
        action);
  }


  private void playerReturnsWithoutKillingTheImperialScientistOrWithoutGoblet(
      SpeakerNPC npc) {
    final ChatCondition condition = new AndCondition(
        new GreetingMatchesNameCondition(npc.getName()),
        new QuestStateStartsWithCondition(QUEST_SLOT, "kill_scientist"),
        new NotCondition(
            new AndCondition(
                    new KilledForQuestCondition(QUEST_SLOT, 1),
                    new PlayerHasItemWithHimCondition("goblet")))
      );
    npc.add(ConversationStates.IDLE, ConversationPhrases.GREETING_MESSAGES,
        condition, ConversationStates.IDLE,
        "I am only in pain. Kill my brother and bring me his blood. It's all I want now.",
        null);
  }
 
  private void playerReturnsWithLetter(final SpeakerNPC npc) {
    final ChatCondition condition = new AndCondition(
        new QuestStateStartsWithCondition(QUEST_SLOT, "find_vera"),
        new PlayerHasItemWithHimCondition("note")
      );
   
    final ChatAction action = new MultipleActions(
          new SetQuestAction(QUEST_SLOT, 0, "kill_scientist"),
          new StartRecordingKillsAction(QUEST_SLOT, 1, "Sergej Elos", 0, 1),
          new DropItemAction("note")
        );
    npc.add(ConversationStates.IDLE, ConversationPhrases.GREETING_MESSAGES,
        new AndCondition(new GreetingMatchesNameCondition(npc.getName()), condition),
        ConversationStates.INFORMATION_2,
        "Hello! Do you have anything for me?",
        null);
   
    npc.add(ConversationStates.INFORMATION_2, Arrays.asList("letter", "yes", "note"),
        condition,
        ConversationStates.ATTENDING,
        "Oh no! I feel the pain. I do not need to create those beautiful jewelled legs now. " +
        "I want to transform them. I want to make them a symbol of pain. You! Go kill my brother, " +
        "the Imperial Scientist Sergej Elos. Give me his blood.",
        action);
   
    npc.add(ConversationStates.ATTENDING, ConversationPhrases.GOODBYE_MESSAGES,
        new QuestInStateCondition(QUEST_SLOT, 0, "kill_scientist"),
        ConversationStates.INFORMATION_2,
        "Do it!",
        null);
  }
 
  private void playerReturnsWithoutLetter(final SpeakerNPC npc) {
    final ChatCondition condition = new AndCondition(new GreetingMatchesNameCondition(npc.getName()),
        new QuestStateStartsWithCondition(QUEST_SLOT, "find_vera"),
        new NotCondition(new PlayerHasItemWithHimCondition("note"))
      );
    npc.add(ConversationStates.IDLE, ConversationPhrases.GREETING_MESSAGES,
        condition,
        ConversationStates.IDLE,
        "Please ask Mayor Sakhs about my wife Vera.",
        null);
  }

  private void playerVisitsMayorSakhs(final SpeakerNPC npc) {
    final ChatAction action = new ChatAction() {
      public void fire(final Player player, final Sentence sentence, final EventRaiser npc) {
        final Item item = SingletonRepository.getEntityManager().getItem("note");
        item.setInfoString(player.getName());
        item.setDescription(LETTER_DESCRIPTION);
        item.setBoundTo(player.getName());
        player.equipOrPutOnGround(item);
      }
    };
    npc.add(ConversationStates.ATTENDING, "Vera",
        new QuestStateStartsWithCondition(QUEST_SLOT, "find_vera"),
        ConversationStates.ATTENDING,
        "What? How do you know her? Well it is a sad story." +
        " She was picking arandula for Ilisa (they were friends)" +
        " and she saw the catacombs entrance. 3 months later a" +
        " young hero saw her, and she was a vampirette. What a" +
        " sad story. I kept this for her husband. A letter. " +
        "I think he is in Kalavan." ,
        action);
  }

  private void playerReturnsAfterGivingWhenFinished(final SpeakerNPC npc) {
    final ChatCondition condition = new AndCondition(
        new QuestStateStartsWithCondition(QUEST_SLOT, "making;"),
        new TimePassedCondition(QUEST_SLOT, 1, REQUIRED_MINUTES)
      );
    final ChatAction action = new SetQuestAction(QUEST_SLOT,"find_vera");
    npc.add(ConversationStates.IDLE, ConversationPhrases.GREETING_MESSAGES,
        new AndCondition(new GreetingMatchesNameCondition(npc.getName()), condition),
        ConversationStates.INFORMATION_1,
        "I finished the legs. But I cannot trust you. Before I give the" +
        " jewelled legs to you, I need a message from my darling. Ask Mayor" +
        " Sakhs for Vera. Can you do that for me?",
        null);
   
    npc.add(ConversationStates.INFORMATION_1, ConversationPhrases.YES_MESSAGES,
        condition,
        ConversationStates.IDLE,
        "Oh, thank you. I am waiting.",
        action);
   
    npc.add(ConversationStates.INFORMATION_1, ConversationPhrases.NO_MESSAGES,
        condition,
        ConversationStates.IDLE,
        "Pah! Bye!",
        null);
  }

  private void playerReturnsAfterGivingTooEarly(final SpeakerNPC npc) {
    final ChatCondition condition = new AndCondition(new GreetingMatchesNameCondition(npc.getName()),
        new QuestStateStartsWithCondition(QUEST_SLOT, "making;"),
        new NotCondition(new TimePassedCondition(QUEST_SLOT, 1, REQUIRED_MINUTES))
      );
    npc.add(ConversationStates.IDLE, ConversationPhrases.GREETING_MESSAGES,
        condition,
        ConversationStates.IDLE,
        null,
        new SayTimeRemainingAction(QUEST_SLOT, 1, REQUIRED_MINUTES, "Do you think I can work that fast? Go away. " +
                "Come back in"));
  }
 
  private void bringItemsPhase(final SpeakerNPC npc) {
    //condition for quest being active and in item collection phase
    ChatCondition itemPhaseCondition = getConditionForBeingInCollectionPhase();
   
    //player returns during item collection phase
    npc.add(ConversationStates.IDLE, ConversationPhrases.GREETING_MESSAGES,
        new AndCondition(new GreetingMatchesNameCondition(npc.getName()),
            itemPhaseCondition),
        ConversationStates.QUESTION_1,
        "Hello. Do you have any #items I need for the jewelled legs?",
        null);
   
    //player asks for items
    npc.add(ConversationStates.QUESTION_1, Arrays.asList("items","item"),
        itemPhaseCondition,
        ConversationStates.QUESTION_1,
        null,
        new SayRequiredItemsFromCollectionAction(QUEST_SLOT, "Please return when you have anything I need for the jewelled legs. I need [items]."));
   
    //player says no
    npc.add(ConversationStates.QUESTION_1, ConversationPhrases.NO_MESSAGES,
        itemPhaseCondition,
        ConversationStates.IDLE,
        "What a wasteful child.",
        null);
   
    //player says yes
    npc.add(ConversationStates.QUESTION_1, ConversationPhrases.YES_MESSAGES,
        itemPhaseCondition,
        ConversationStates.QUESTION_1,
        "Fine! So what did you bring with you?",
        null);
   
    //add transition for each item
    final ItemCollection items = new ItemCollection();
    items.addFromQuestStateString(NEEDED_ITEMS);
    for (final Map.Entry<String, Integer> item : items.entrySet()) {
      npc.add(ConversationStates.QUESTION_1, item.getKey(), null,
          ConversationStates.QUESTION_1, null,
          new CollectRequestedItemsAction(
              item.getKey(), QUEST_SLOT,
              "Good, do you have anything else?",
              "You have already brought that!",
              new MultipleActions(
                  new SetQuestAction(QUEST_SLOT,"legs"),
                  new SayTextAction("I am a stupid fool too much in love with my wife Vera to remember, of course these legs also need a base to add " +
                      "the jewels to. Please return with a pair of shadow legs. Bye.")), ConversationStates.IDLE
              ));
    }
  }
 
 
//                                new SetQuestAction(QUEST_SLOT,"making;"), new SetQuestToTimeStampAction(QUEST_SLOT, 1),
  /**
   * Creates a condition for quest being active and in item collection phase
   * @return the condition
   */
  private AndCondition getConditionForBeingInCollectionPhase() {
    return new AndCondition(
                          new QuestActiveCondition(QUEST_SLOT),
                          new NotCondition(
                              new QuestStateStartsWithCondition(QUEST_SLOT,"making;")
                                  ),
                          new NotCondition(
                              new QuestStateStartsWithCondition(QUEST_SLOT,"decorating;")
                                  ),
                          new NotCondition(
                              new QuestStateStartsWithCondition(QUEST_SLOT,"find_vera")
                                  ),
                          new NotCondition(
                              new QuestStateStartsWithCondition(QUEST_SLOT,"kill_scientist")
                                  ),
                          new NotCondition(
                              new QuestStateStartsWithCondition(QUEST_SLOT,"legs")
                                          )
                              );
  }
 
  private void playerReturnsAfterRequestForLegs(final SpeakerNPC npc) {
  //player returns without legs
  final AndCondition nolegscondition = new AndCondition(new GreetingMatchesNameCondition(npc.getName()),
                  new QuestInStateCondition(QUEST_SLOT, "legs"),
                  new NotCondition(new PlayerHasItemWithHimCondition("shadow legs"))
                  );
  npc.add(ConversationStates.IDLE, ConversationPhrases.GREETING_MESSAGES,
      nolegscondition,
      ConversationStates.IDLE,
      "Hello again. Please return when you have the shadow legs, a base for me to add jewels to make jewelled legs for Vera.",
      null);   
   
  //player returns with legs
  final AndCondition legscondition = new AndCondition(new GreetingMatchesNameCondition(npc.getName()),
                new QuestInStateCondition(QUEST_SLOT, "legs"),
                new PlayerHasItemWithHimCondition("shadow legs")
                );
  final ChatAction action = new MultipleActions(
  new SetQuestAction(QUEST_SLOT,"making;"),
  new SetQuestToTimeStampAction(QUEST_SLOT, 1),
  new DropItemAction("shadow legs"));
  npc.add(ConversationStates.IDLE, ConversationPhrases.GREETING_MESSAGES,
      legscondition,
      ConversationStates.IDLE,
      "The shadow legs! Wonderful! I will start my work. I can do this in very little time with the help of technology! "
      "Please come back in 20 minutes.",
      action);
  }

  private void startOfQuest(final SpeakerNPC npc) {
    npc.add(ConversationStates.IDLE,
        ConversationPhrases.GREETING_MESSAGES,
        new AndCondition(new GreetingMatchesNameCondition(npc.getName()),
            new QuestNotStartedCondition(QUEST_SLOT)),
        ConversationStates.ATTENDING,
        "Go away!",null);

    //offer the quest
    npc.add(ConversationStates.ATTENDING,
        ConversationPhrases.QUEST_MESSAGES,
        new QuestNotStartedCondition(QUEST_SLOT),
        ConversationStates.QUEST_OFFERED,
        "So...looks like you want to help me?",null);
   
    //accept the quest
    npc.add(ConversationStates.QUEST_OFFERED,
        ConversationPhrases.YES_MESSAGES,
        null,
        ConversationStates.QUEST_STARTED,
        "My wife is living in Semos City. She loves gems. Can you bring me some #gems that I need to make a " +
        "pair of precious #legs?" ,
        null);
   
    // #gems
    npc.add(ConversationStates.QUEST_STARTED,
        Arrays.asList("gem","gems"),
        null,
        ConversationStates.QUEST_STARTED,
        "I need an emerald, an obsidian, a sapphire, 2 carbuncles, 20 gold bars and one mithril bar." +
        " Can you do that for my wife?",
        null);
   
    // #legs
    npc.add(ConversationStates.QUEST_STARTED,
        Arrays.asList("leg","legs"),
        null,
        ConversationStates.QUEST_STARTED,
        "Jewelled legs. I need an emerald, an obsidian, a sapphire, 2 carbuncles, 20 gold bars and one mithril bar." +
        " Can you do that for my wife? Can you bring what I need?",
        null);
   
    //yes, no after start of quest
    npc.add(ConversationStates.QUEST_STARTED,
        ConversationPhrases.YES_MESSAGES,
        null,
        ConversationStates.IDLE,
        "I am waiting, Semos man." ,
        new SetQuestAction(QUEST_SLOT, NEEDED_ITEMS));
   
    npc.add(ConversationStates.QUEST_STARTED,
        ConversationPhrases.NO_MESSAGES,
        null,
        ConversationStates.QUEST_STARTED,
        "Go away before I kill you!" ,
        new SetQuestAndModifyKarmaAction(QUEST_SLOT, "rejected", -10.0));
   
    //reject the quest
    npc.add(ConversationStates.QUEST_OFFERED,
        ConversationPhrases.NO_MESSAGES,
        null,
        ConversationStates.ATTENDING,
        "If you change your mind please ask me again..." ,
        new SetQuestAndModifyKarmaAction(QUEST_SLOT, "rejected", -10.0));
  }
 
  private void playerReturnsAfterCompletingQuest(final SpeakerNPC npc) {
    // after finishing the quest, just tell them to go away, and mean it.
    npc.add(ConversationStates.IDLE,
        ConversationPhrases.GREETING_MESSAGES,
        new AndCondition(new GreetingMatchesNameCondition(npc.getName()),
            new QuestCompletedCondition(QUEST_SLOT)),
        ConversationStates.IDLE,
        "Go away!",null);
  }
 
  // The items and surviving in the basement mean we shouldn't direct them till level 100 or so
  @Override
  public int getMinLevel() {
    return 100;
  }
 
  @Override
  public String getRegion() {
    return Region.KALAVAN;
  }
}
TOP

Related Classes of games.stendhal.server.maps.quests.SadScientist

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.