Kovitikus

Riane NPC Module

Apr 11th, 2020
114
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.73 KB | None | 0 0
  1. import evennia
  2. from typeclasses.characters import Character
  3. from evennia import DefaultCharacter
  4. from evennia.scripts.tickerhandler import TICKER_HANDLER
  5. from evennia import create_script
  6. import random
  7. from typeclasses import exits
  8. from evennia import logger
  9.  
  10. class CMob(DefaultCharacter):
  11.     """
  12.  
  13.    TO DO:
  14.    Create attack function
  15.    Create death function
  16.    Plug in fight script
  17.  
  18.    """
  19.  
  20.     def at_object_creation(self):
  21.         # BASICS DB
  22.         self.db.states = ["state_idle", "state_wander", "state_job", "state_hunt", "state_attack", "state_death"]
  23.         self.db.ticker_interval = random.randint(60,90)
  24.         self.db.default_state = "state_idle"
  25.         self.db.current_state = "state_idle"
  26.         self.db.profession = 3
  27.         self.db.race = 3
  28.         self.db.level = 81
  29.         self.db.curhp = 100
  30.         self.db.maxhp = 100
  31.         self.db.resources = 0
  32.         self.db.curres = 0
  33.         self.db.desc = "An average person."
  34.         # INTERACTION DB
  35.         self.db.current_target = None
  36.         self.db.greets = True
  37.         self.db.greetmsg = [f"Good day to you," ,f"Hello, there," ,f"Greetings,"]
  38.         self.db.custom_response = "|mGuy|n says, \"|gGreat! You'll learn more about |cgreet|n|ging later in the tutorial.|n\""
  39.         self.db.greet_name = True
  40.         self.db.cangive = False
  41.         # MOVEMENT DB
  42.         self.db.mobile = False   # If Mob, make sure this is set to FALSE when combat begins!
  43.         self.db.zone = "anubian_farm"
  44.         self.db.spawn_location = "spawn room" # This will be used by the spawner script
  45.         self.db.idle = True
  46.         self.db.idle_list = [
  47.             'whistles a merry tune.', 'looks around cheerfully.', 'hums to himself.', 'pauses to scratch his groin.',\
  48.                'checks his watch.', 'bops his head to an imaginary beat.', 'asks, |G"anyone play a good video game lately?"|g.']
  49.         # COMBAT DB
  50.         self.db.is_aggressive = False
  51.         self.db.is_suspicious = False
  52.         self.db.is_fighting = False  
  53.         self.db.can_die = False
  54.         self.db.can_loot = False
  55.         self.db.loot = []
  56.         self.db.credits = random.randint(2, 12) # random number for credits in loot
  57.         self.db.dead = False
  58.         self.db.spawn_location = "spawn room" # assign this by the spawner script
  59.         self.db.ticker_despawn = random.randint(120, 180)
  60.         # JOBS DB
  61.         self.db.hasjob = True
  62.         self.db.job_script = None
  63.         # TICKER CONTROLS      
  64.         self.ticker_start()
  65.     def ticker_start(self):
  66.         """
  67.        This just gets the ticker going. The same ticker is used for all states.
  68.        """
  69.         TICKER_HANDLER.add(interval=self.db.ticker_interval, callback=self.do_action, idstring="npc_ticker")
  70.    
  71.     def ticker_stop(self):
  72.         """
  73.        Stops the ticker. Good for things like when combat starts.
  74.        """
  75.         TICKER_HANDLER.remove(interval=self.db.ticker_interval, callback=self.do_action, idstring="npc_ticker")
  76.  
  77.     def do_action(self):
  78.        
  79.         current_state = self.db.current_state
  80.         try:
  81.             # find a method on this class with the same name as the state, like "state_idle".
  82.             state_method = getattr(self, current_state)
  83.         except AttributeError:
  84.             logger.log_trace(f"Erroneous state for NPC {self.key}")            
  85.             return
  86.         try:
  87.             # we fire the state-method we just dug out
  88.             state_method()
  89.         except Exception:
  90.             logger.log_trace(f"Error when running the {state_method}() on NPC {self.key}")
  91.            
  92.     # SET STATE
  93.     def set_state(self, statename, target=None):
  94.         """
  95.        This is something we should be able to set with a custom Command, something like
  96.            setstate <npcname> = idle
  97.            setstate <npcname> = idle:target
  98.  
  99.        Args:
  100.            statename (str): The name of the state. Must be one of the allowed states.
  101.            target (Object): If this state has a target, the Command should get that and
  102.                supply it here as well.
  103.                
  104.        Raises:
  105.            RuntimeError: On invalid input. The calling command can catch and show this
  106.                to the user.
  107.        """
  108.         statename = statename.lower()  # make case not matter
  109.         if not statename in self.db.states:
  110.             raise RuntimeError("This is not a valid state")
  111.         self.db.current_state = statename
  112.         self.db.current_target = target
  113.  
  114.     # WANDER STATE
  115.     def state_wander(self):
  116.         zone = self.db.zone
  117.         move_chance = random.randint(1,5)
  118.         if self.db.mobile:
  119.             if move_chance >= 4:      
  120.                 exit_list = [myexit for myexit in self.location.exits if self.check_zone(myexit.destination)]
  121.                 if exit_list:
  122.                     new_exit = random.choice(exit_list)
  123.                     self.location.msg_contents(f"|m{self.name}|n creeps away.")
  124.                     self.move_to(new_exit.destination)
  125.                     self.location.msg_contents(f"|m{self.name}|n scans the area.")
  126.                 else:
  127.                     self.location.msg_contents(f"|m{self.name}|n sneaks away.")
  128.                     self.move_to(self.home)
  129.                     self.location.msg_contents(f"|m{self.name}|n scans the area.")
  130.         if self.db.aggressive:
  131.             self.set_state("state_hunt")
  132.         elif self.db.idle:
  133.             self.set_state("state_idle")
  134.     # IDLE STATE
  135.     def state_idle(self):
  136.         idle_msg = random.choice(self.db.idle_list)
  137.         self.location.msg_contents(f"|m{self.name}|n {idle_msg}")
  138.  
  139.     # JOB STATE
  140.     def state_job(self, target):
  141.         self.db.current_target = target
  142.        
  143.         if self.db.hasjob:
  144.             logger.log_trace(f"{self.key} has a job.")
  145.             if not self.db.job_script: # No script created yet, make it
  146.                 script = "typeclasses.jobs_script"
  147.                 try:
  148.                     create_script(script, obj=self, persistent=True)
  149.                     self.db.job_script = script
  150.                     target.db.jobs_doing.append(script)
  151.                     logger.log_trace(f"{self.key} created {script} Attenpting to access...")
  152.                     typeclasses.jobs_script.JobScript.asked_for_job(self)
  153.                 except:
  154.                     logger.log_trace(f"{self.key} failed to create {script}.")
  155.  
  156.             elif self.db.job_script: # Script exists, just check it now.
  157.                 logger.log_trace(f"{self.key} attempting to access: typeclasses.jobs_script.JobScript.asked_for_job(self).")
  158.                 typeclasses.jobs_script.JobScript.asked_for_job(self)
  159.  
  160.         elif not self.db.hasjob:
  161.             target.msg(f"|m{self.name}|n thinks for a moment, then says, |g\"I'm afraid I don't have anything for you, {target.name}.\"|n")
  162.             logger.log_trace(f"{self.key} has no jobs.")
  163.             script.JobGive.asked_for_job(target)
  164.         else:
  165.             logger.log_trace(f"{self.key} does not have a job for {target}.")
  166.             # inform player that the npc has no job for them.
  167.         getstate = self.db.default_state
  168.         self.set_state(getstate)
  169.    
  170.     # HUNT STATE
  171.     def hunt(self):
  172.         if not self.db.dead and self.db.aggressive:
  173.             target = self.get_target(self.location)
  174.             if target:
  175.                 target.msg(f"|m{self.name}|n moves to attack you!")
  176.                 self.set_state("state_attack")
  177.             elif self.db.idle:
  178.                 self.set_state("state_idle")
  179.  
  180.     def get_target(self, location):
  181.         targets = [obj for obj in location.contents_get(exclude=self) if obj.has_account and not obj.is_superuser]
  182.         return targets[0] if targets else None
  183.     # ATTACK STATE      
  184.     def state_attack(self, target):
  185.         """
  186.  
  187.        Start attack setup, then call the fighting script.
  188.  
  189.        """
  190.        
  191.         #if flee:
  192.             #if mobile:
  193.                 #self.set_ticker(interval=self.db.ticker_interval, callback=self.wander, idstring="wandering_mob", persistent=True)
  194.     # DEATH STATE
  195.     def state_death(self):
  196.         self.location.msg_contents(f"|m|m{self.name}|n|n has died!")
  197.         self.location.msg_contents(f"|m{self.name}|n falls to the ground, lifeless.")        
  198.         #set a timer to destroy
  199.         self.db.mobile = False
  200.         self.db.dead = True
  201.         self.db.canloot = True
  202.         self.set_ticker(self.db.ticker_despawn, "remove_mob")
  203.  
  204.     # CHECK ZONE
  205.     def check_zone(self, destination):
  206.         dest = destination.tags.get(category="pverooms")  # destination is the actual object 'room'
  207.         if dest is not None:
  208.             return True
  209.         else:
  210.             return False
  211.     # CHARACTER ENTERED ROOM
  212.     def at_char_entered(self, character):
  213.         """
  214.        Character entered the same room as the mob
  215.        Check if the character is a player by running get_target()
  216.        Check if mob is aggressive
  217.        If mob is aggressive, run the attack function
  218.        If the mob is not aggressive but suspicious,
  219.        just look at the target.
  220.        """
  221.         target = self.get_target(self.location)
  222.         if self.db.aggressive:
  223.             if target:
  224.                 TICKER_HANDLER.remove(idstring="wandering_npc")
  225.                 target.msg(f"|m{self.name}|n attacks you!")
  226.                 self.start_attacking(self, target)
  227.                 return
  228.         elif self.db.is_suspicious:
  229.             self.location.msg_contents(f"|m{self.name}|n looks at {character}.", exclude=target)
  230.             target.msg(f"|m{self.name}|n looks at you.")
  231.             pass
  232.     # REMOVE SELF (DEATH)
  233.     def remove_mob(self, *args, **kwargs):
  234.         TICKER_HANDLER.remove(idstring="wandering_mob")
  235.     # RETURN APPEARANCE
  236.     def return_appearance(self, looker):
  237.         text = super().return_appearance(looker)
  238.         lvl = int(self.db.level)
  239.         if not self.db.dead:
  240.             if lvl < 5:
  241.                 cinfo = "\n|YThey are very frail looking.|n"
  242.             elif lvl < 10:
  243.                 cinfo = "\n|YThey look pretty weak.|n"
  244.             elif lvl < 20:
  245.                 cinfo = "\n|YThey don't seem terribly strong.|n"
  246.             elif lvl < 30:
  247.                 cinfo = "\n|YThey look somewhat skilled.|n"
  248.             elif lvl < 40:
  249.                 cinfo = "\n|YThey seem like they could hold their own.|n"
  250.             elif lvl < 50:
  251.                 cinfo = "\n|YThey appear decently skilled.|n"
  252.             elif lvl < 60:
  253.                 cinfo = "\n|YThey look fairly strong.|n"
  254.             elif lvl < 70:
  255.                 cinfo = "\n|YThey seem pretty tough.|n"
  256.             elif lvl < 80:
  257.                 cinfo = "\n|YSomething tells you they're very skilled.|n"
  258.             elif lvl < 90:
  259.                 cinfo = "\n|YThey have a powerful air to them.|n"
  260.             elif lvl < 100:
  261.                 cinfo = "\n|YThey are God-like in power.|n"
  262.         else:
  263.             cinfo = "\n|yThey lay lifeless upon the ground, very dead.|n"
  264.         if "\n" in text:
  265.             # text is multi-line, add details after first line
  266.             first_line, rest = text.split("\n", 1)
  267.             text = first_line + cinfo + "\n" + rest
  268.         else:
  269.             # text is only one line; add details to end
  270.             text += cinfo
  271.         return text
  272.     # RESPOND TO GREET
  273.     def greeting(self, target):
  274.         logger.log_trace(f"{target} greeted {self.name}.")
  275.  
  276.         self.db.current_target = target
  277.         response = random.choice(self.db.greetmsg)
  278.         customresponse = self.db.custom_response
  279.         if self.db.greet_name:
  280.             text = (f"|m{self.name}|n says, |g'") + (response) + (f" {target}.'|n")
  281.             target.msg(text)
  282.         else:
  283.             text = "f" + (customresponse)
  284.             target.msg(text)
Add Comment
Please, Sign In to add comment