Example #1
0
    def finalize(self):
        super(MagicDamageConsequence, self).finalize()

        from typeclasses.scripts.combat import attacks, combat_settings

        victims = [participant.character for participant in self.participants]
        names = [obj.name for obj in victims]
        commafied_names = commafy(names)

        attack = attacks.Attack(targets=victims,
                                affect_real_dmg=True,
                                damage=self.damage,
                                use_mitigation=False,
                                can_kill=True,
                                private=False,
                                story="Magic has consequences!",
                                attack_tags=self.attack_tags)
        try:
            attack.execute()
        except combat_settings.CombatError as err:
            logger.log_err("Combat error when applying magical damage: " +
                           str(err))
            inform_staff(
                "|rCombat Error!|n Tried to apply %d damage to %s, but got error %s"
                % (self.damage, commafied_names, str(err)))
        else:
            part = "was"
            if len(victims) > 1:
                part = "were"
            inform_staff(
                "|y%s|n %s harmed for %d by a failed magical working." %
                (commafied_names, part, self.damage))
Example #2
0
 def bb_orgstance(self, poster_obj, org, msg, postnum):
     """
     Post teeny commentary as addendum to board message.
     
     Args:
         poster_obj: Character
         org: Organization
         msg: str
         postnum: int
     """
     tagname = "%s_comment" % org
     # I love you so much <3 Do not let orange text bother you!
     # I love you too <3 Because board is calling this, board is now self.
     post = self.get_post(poster_obj, postnum)
     if not post:
         return
     if post.tags.get(tagname, category="org_comment"):
         poster_obj.msg("{w%s{n has already declared a position on this matter." % org)
         return
     if not org.access(poster_obj, "declarations"):
         poster_obj.msg("Your {w%s{n rank isn't yet high enough to make declarations on their behalf." % org)
         return
     if len(msg) > 280:
         poster_obj.msg("That message is too long for a brief declaration.")
         return
     if org.secret:
         post.db_message += "\n\n--- {w%s{n Stance ---\n%s" % (org, msg)
     else:
         post.db_message += "\n\n--- {w%s{n Stance (from %s) ---\n%s" % (org, poster_obj, msg)
     post.tags.add("%s_comment" % org, category="org_comment")
     post.save()
     poster_obj.msg("{w%s{n successfully declared a stance on '%s'." % (org, post.db_header))
     self.notify_subs("{w%s has commented upon proclamation %s.{n" % (org, postnum))
     from server.utils.arx_utils import inform_staff
     inform_staff("{c%s {whas posted an org stance for %s." % (poster_obj, org))
Example #3
0
 def perform(self):
     super(AnimaRitualEffect, self).perform()
     num_rituals = self.lead.anima_rituals_this_week + 1
     self.final_value = self.strength / num_rituals
     inform_staff(
         "Anima Ritual story by %s: %s" % (self.lead.character.key, self.story)
     )
Example #4
0
    def do_dominion_events(self):
        """Does all the dominion weekly events"""
        for owner in AssetOwner.objects.all():
            owner.prestige_decay()

        for owner in AssetOwner.objects.filter(
                Q(organization_owner__isnull=False)
                | (Q(player__player__roster__roster__name="Active")
                   & Q(player__player__roster__frozen=False))).distinct():
            try:
                owner.do_weekly_adjustment(self.db.week, self.inform_creator)
            except Exception as err:
                traceback.print_exc()
                print("Error in %s's weekly adjustment: %s" % (owner, err))
        # resets the weekly record of work command
        cache_safe_update(Member.objects.filter(deguilded=False),
                          work_this_week=0,
                          investment_this_week=0)
        # decrement timer of limited transactions, remove transactions that are over
        AccountTransaction.objects.filter(repetitions_left__gt=0).update(
            repetitions_left=F('repetitions_left') - 1)
        AccountTransaction.objects.filter(repetitions_left=0).delete()
        for army in Army.objects.filter(orders__week=self.db.week):
            try:
                army.execute_orders(self.db.week)
            except Exception as err:
                traceback.print_exc()
                print("Error in %s's army orders: %s" % (army, err))
        old_orders = Orders.objects.filter(complete=True,
                                           week__lt=self.db.week - 4)
        old_orders.delete()
        inform_staff("Dominion weekly events processed for week %s." %
                     self.db.week)
Example #5
0
    def death_process(self, *args, **kwargs):
        """
        This object dying. Set its state to dead, send out
        death message to location. Add death commandset.

        Returns:
            True if the character is dead, indicating other rolls for
            unconsciousness and the like should not proceed. False if
            they lived and should check for other effects.
        """
        if self.dead:
            return True
        self.health_status.set_dead()
        self.db.container = True
        if self.location:
            self.location.msg_contents("{r%s has died.{n" % self.name)
        try:
            from commands.cmdsets import death

            cmds = death.DeathCmdSet
            if cmds.key not in [ob.key for ob in self.cmdset.all()]:
                self.cmdset.add(cmds, permanent=True)
        except Exception as err:
            print("<<ERROR>>: Error when importing death cmdset: %s" % err)
        from server.utils.arx_utils import inform_staff

        if not self.is_npc:
            inform_staff("{rDeath{n: Character {c%s{n has died." % self.key)
        self.post_death()
        return True
Example #6
0
 def post_top_rpers(self):
     """
     Post ourselves to a bulletin board to celebrate the highest voted RPers
     this week. We post how much xp each player earned, not how many votes
     they received.
     """
     import operator
     # this will create a sorted list of tuples of (id, votes), sorted by xp, highest to lowest
     sorted_xp = sorted(self.ndb.xp.items(),
                        key=operator.itemgetter(1),
                        reverse=True)
     string = "{wTop RPers this week by XP earned{n".center(60)
     string += "\n{w" + "-" * 60 + "{n\n"
     sorted_xp = sorted_xp[:20]
     num = 0
     for tup in sorted_xp:
         num += 1
         try:
             char = tup[0]
             votes = tup[1]
             name = char.db.longname or char.key
             string += "{w%s){n %-35s {wXP{n: %s\n" % (num, name, votes)
         except AttributeError:
             print("Could not find character of id %s during posting." %
                   str(tup[0]))
     board = BBoard.objects.get(db_key__iexact=VOTES_BOARD_NAME)
     board.bb_post(poster_obj=self,
                   msg=string,
                   subject="Weekly Votes",
                   poster_name="Vote Results")
     inform_staff("Vote process awards complete. Posted on %s." % board)
Example #7
0
    def weekly_resonance_update(self):

        results = []

        for practitioner in self.get_active_practitioners().all():
            result = self.advance_weekly_resonance(practitioner)
            if result:
                results.append(result)

        from typeclasses.bulletin_board.bboard import BBoard
        board = BBoard.objects.get(db_key__iexact="staff")
        table = EvTable("{wName{n",
                        "{wGain{n",
                        "{wUnspent{n",
                        "{wMax{n",
                        border="cells",
                        width=78)
        for result in results:
            table.add_row(result['name'], result['gain'],
                          "%.2f" % result['resonance'], result['potential'])
        board.bb_post(poster_obj=self,
                      msg=str(table),
                      subject="Magic Resonance Gains",
                      poster_name="Magic System")
        inform_staff("List of magic resonance gains posted.")
Example #8
0
    def weekly_practice_update(self):

        results = []
        for practitioner in self.get_active_practitioners().all():
            result = self.advance_weekly_practice(practitioner)
            if result:
                results.append(result)

        from typeclasses.bulletin_board.bboard import BBoard
        board = BBoard.objects.get(db_key__iexact="staff")
        table = EvTable(border="cells", width=78)
        table.add_column("|wName|n", width=20, valign='t')
        table.add_column("|wPractices|n", valign='t')
        for result in results:
            subtable = EvTable(border=None)
            for node in result['practices']:
                subtable.add_row(node['node'], "%.2f gain" % node['gain'],
                                 "%.2f total" % node['resonance'],
                                 node['teacher'])
            table.add_row(result['name'], str(subtable))

        SkillNodeResonance.objects.filter(
            teaching_multiplier__isnull=False).update(teaching_multiplier=None,
                                                      taught_by=None,
                                                      taught_on=None)

        board.bb_post(poster_obj=self,
                      msg=str(table),
                      subject="Magic Practice Results",
                      poster_name="Magic System")
        inform_staff("List of magic practice results posted.")
Example #9
0
    def get_emit_msg(cls, fashion_model, thing, org, fame):
        """
        Returns the string a room sees when the fashionista models their item
        or outfit. Higher impacts notify staff as well.
            Args:
                fashion_model:  player/account object
                thing:          an item or an outfit
                org:            organization
                fame:           integer
        String interpolation is specific order, eg: "Despite efforts made by
        <name>, modeling <item> on behalf of <org> attracts <adjective> notice."
        Order: fashion model, item/outfit, org, buzz_type (based on fame)
        """
        buzz_level = cls.granulate_fame(fame)
        buzzy = cls.BUZZIES[buzz_level]
        color = buzzy[1]
        diva = str(fashion_model)
        thing = "'%s%s'" % (str(thing), color)
        msg = color + "[Fashion] "
        msg += buzzy[2] % (diva, thing, org, buzzy[0])
        if buzz_level > 4:
            from server.utils.arx_utils import inform_staff

            inform_staff(msg)
        return msg
Example #10
0
 def func(self):
     """Execute command."""
     caller = self.caller
     targ = caller.search(self.lhs)
     if not targ:
         return
     inform_msg = ""
     try:
         rhs = self.rhs.split("/", 1)
         val = int(rhs[0])
         if len(rhs) > 1:
             inform_msg = rhs[1]
         if not val:
             raise ValueError
     except (TypeError, ValueError, AttributeError):
         self.msg("Invalid syntax: Must have an xp amount.")
         return
     char = targ.char_ob
     if not char:
         caller.msg("No active character found for that player.")
         return
     char.adjust_xp(val)
     if inform_msg:
         msg = "You have been awarded %d xp: %s" % (val, inform_msg)
         targ.inform(msg, category="XP")
         inform_msg = " Message sent to player: %s" % inform_msg
     caller.msg("Giving %s xp to %s.%s" % (val, char, inform_msg))
     inform_staff("%s has adjusted %s's xp by %s.%s" %
                  (caller, char, val, inform_msg))
Example #11
0
 def save(self, commit=True):
     clue = super(ClueCreateForm, self).save(commit)
     clue.author = self.author
     clue.save()
     revelation = self.cleaned_data.get('revelation')
     clue.usage.create(revelation=revelation)
     clue.discoveries.create(character=self.author,
                             discovery_method="author")
     inform_staff("Clue '%s' created for revelation '%s'." %
                  (clue, revelation))
     return clue
Example #12
0
 def post_inactives(self):
     """Makes a board post of inactive characters"""
     date = datetime.now()
     cutoffdate = date - timedelta(days=30)
     qs = Account.objects.filter(roster__roster__name="Active", last_login__isnull=False).filter(
         last_login__lte=cutoffdate)
     board = BBoard.objects.get(db_key__iexact="staff")
     table = EvTable("{wName{n", "{wLast Login Date{n", border="cells", width=78)
     for ob in qs:
         table.add_row(ob.key.capitalize(), ob.last_login.strftime("%x"))
     board.bb_post(poster_obj=self, msg=str(table), subject="Inactive List", poster_name="Inactives")
     inform_staff("List of Inactive Characters posted.")
Example #13
0
 def save(self, commit=True):
     revelation = super(RevelationCreateForm, self).save(commit)
     revelation.author = self.author
     revelation.save()
     plot = self.cleaned_data.get('plot')
     gm_notes = self.cleaned_data.get('plot_gm_notes', "")
     revelation.plot_involvement.create(plot=plot, gm_notes=gm_notes)
     revelation.discoveries.create(character=self.author,
                                   discovery_method="author")
     inform_staff("Revelation '%s' created for plot '%s'." %
                  (revelation, plot))
     return revelation
Example #14
0
    def unpack_oldest_pending_messenger(self, msgtuple):
        """
        A pending messenger is a tuple of several different values. We'll return values for any that we have, and
        defaults for everything else.
        Args:
            msgtuple: An iterable of values that we'll unpack.

        Returns:
            A string representing the messenger name, the Messenger object itself, any delivered object, silver,
            a tuple of crafting materials and their amount, and who this was forwarded by, if anyone.
        """
        messenger_name = "A messenger"
        msg = None
        delivered_object = None
        money = None
        mats = None
        forwarded_by = None
        try:
            import numbers

            msg = msgtuple[0]
            if msg and hasattr(msg, "id") and msg.id:
                # Very important: The Msg object is unpickled in Attributes as a Msg. It MUST be reloaded as its proxy
                msg = reload_model_as_proxy(msg)
            delivered_object = msgtuple[1]
            money_tuple = msgtuple[2]
            # check if the messenger is of old format, pre-conversion. Possible to sit in database for a long time
            if isinstance(money_tuple, numbers.Real):
                money = money_tuple
            elif money_tuple:
                money = money_tuple[0]
                if len(money_tuple) > 1:
                    mats = money_tuple[1]
                    try:
                        mats = (CraftingMaterialType.objects.get(id=mats[0]),
                                mats[1])
                    except (CraftingMaterialType.DoesNotExist, TypeError,
                            ValueError):
                        mats = None
            messenger_name = msgtuple[3] or "A messenger"
            forwarded_by = msgtuple[4]
        except IndexError:
            pass
        except (TypeError, AttributeError):
            import traceback

            traceback.print_exc()
            self.msg(
                "The message object was in the wrong format or deleted, possibly a result of a database error."
            )
            inform_staff("%s received a buggy messenger." % self.obj)
            return
        return msg, delivered_object, money, mats, messenger_name, forwarded_by
Example #15
0
    def award_resources(self, player, xp, xptype="all"):
        """Awards resources to someone based on their xp awards"""
        if xptype not in self.XP_TYPES_FOR_RESOURCES:
            return
        resource_msg = ""
        amt = 0
        try:
            for r_type in ("military", "economic", "social"):
                amt = player.gain_resources(r_type, xp)
            if amt:
                resource_msg = "Based on your number of %s, you have gained %s resources of each type." % (
                    xptype, amt)
        except AttributeError:
            pass
        if resource_msg:
            self.inform_creator.add_player_inform(player,
                                                  resource_msg,
                                                  "Resources",
                                                  week=self.db.week)

    #def post_top_rpers(self):
        """
        Post ourselves to a bulletin board to celebrate the highest voted RPers
        this week. We post how much xp each player earned, not how many votes
        they received.
        """
        import operator
        # this will create a sorted list of tuples of (id, votes), sorted by xp, highest to lowest
        sorted_xp = sorted(self.ndb.xp.items(),
                           key=operator.itemgetter(1),
                           reverse=True)
        string = "{wTop RPers this week by XP earned{n".center(60)
        string += "\n{w" + "-" * 60 + "{n\n"
        sorted_xp = sorted_xp[:20]
        num = 0
        for tup in sorted_xp:
            num += 1
            try:
                char = tup[0]
                votes = tup[1]
                name = char.db.longname or char.key
                string += "{w%s){n %-35s {wXP{n: %s\n" % (num, name, votes)
            except AttributeError:
                print("Could not find character of id %s during posting." %
                      str(tup[0]))
        board = BBoard.objects.get(db_key__iexact=VOTES_BOARD_NAME)
        board.bb_post(poster_obj=self,
                      msg=string,
                      subject="Weekly Votes",
                      poster_name="Vote Results")
        inform_staff("Vote process awards complete. Posted on %s." % board)
Example #16
0
 def do_cleanup(self):
     """Cleans up stale objects from database"""
     date = datetime.now()
     offset = timedelta(days=-30)
     date = date + offset
     try:
         self.cleanup_old_informs(date)
         self.cleanup_old_tickets(date)
         self.cleanup_django_admin_logs(date)
         self.cleanup_soft_deleted_objects()
         self.cleanup_empty_tags()
         self.cleanup_old_praises()
     except Exception as err:
         traceback.print_exc()
         print("Error in cleanup: %s" % err)
     inform_staff("Database cleanup completed.")
Example #17
0
 def save(self, commit=True):
     obj = super(PRPFormBase, self).save(commit=commit)
     tag_names = self.cleaned_data.get('tag_names', "").split(",")
     for tag_name in tag_names:
         tag_name = tag_name.strip()
         try:
             search_tag = SearchTag.objects.get(name__iexact=tag_name)
         except SearchTag.DoesNotExist:
             search_tag = SearchTag.objects.create(name=tag_name)
         except SearchTag.MultipleObjectsReturned:
             search_tag = SearchTag.objects.filter(
                 name__iexact=tag_name).first()
             inform_staff("Multiple '%s' tags exist; using #%s to tag %s." %
                          (tag_name, search_tag.id, obj))
         obj.search_tags.add(search_tag)
     return obj
Example #18
0
 def func(self):
     """Implement the command"""
     caller = self.caller
     targ = caller.search(self.lhs)
     if not targ:
         return
     char = targ.char_ob
     if not char:
         caller.msg("No char.")
         return
     if self.rhs:
         setup_gear_for_char(char, int(self.rhs), reset=True)
     else:
         setup_gear_for_char(char, reset=True)
     caller.msg("Starting money for gear granted to %s." % char)
     arx_utils.inform_staff("%s has given %s money for startgear." % (caller, char))
Example #19
0
 def func(self):
     """Execute command."""
     caller = self.caller
     targ = caller.search(self.lhs)
     val = self.rhs
     if not val or not val.isdigit():
         caller.msg("Invalid syntax.")
         return
     if not targ:
         caller.msg("No player found by that name.")
         return
     char = targ.db.char_ob
     if not char:
         caller.msg("No active character found for that player.")
         return
     char.adjust_xp(int(val))
     caller.msg("Giving %s xp to %s." % (val, char))
     inform_staff("%s has adjusted %s's xp by %s." % (caller, char, val))
Example #20
0
    def bb_orgstance(self, poster_obj, org, msg, postnum):
        """
        Post teeny commentary as addendum to board message.

        Args:
            poster_obj: Character
            org: Organization
            msg: str
            postnum: int
        """
        category = "org_comment"
        tagname = "%s_comment" % org
        # I love you so much <3 Do not let orange text bother you!
        # I love you too <3 Because board is calling this, board is now self.
        post = self.get_post(poster_obj, postnum)
        if not post:
            return
        if post.tags.get(tagname, category):
            poster_obj.msg(
                "|w%s|n has already declared a position on this matter." % org)
            return
        if not org.access(poster_obj, "declarations"):
            poster_obj.msg(
                "Your |w%s|n rank is not set to make declarations on their behalf."
                % org)
            return
        if len(msg) > 280:
            poster_obj.msg("That message is too long for a brief declaration.")
            return
        secret = org.secret
        poster_obj_str = "" if secret else (" via |c%s|n" % poster_obj.key)
        post.db_message += "\n\n--- |w%s|n Stance%s ---\n%s" % (
            org, poster_obj_str, msg)
        post.tags.add(tagname, category)
        post.save()
        success_msg = "|w%s|n%s declared a stance on '%s' (proclamation %s)." % (
            org, poster_obj_str, post.db_header, postnum)
        poster_obj.msg(success_msg)
        self.notify_subs(success_msg)
        from server.utils.arx_utils import inform_staff
        if secret:
            success_msg = "(By |c%s|n) %s" % (poster_obj.key, success_msg)
        inform_staff(success_msg)
Example #21
0
 def death_process(self, *args, **kwargs):
     """
     This object dying. Set its state to dead, send out
     death message to location. Add death commandset.
     """
     if self.db.health_status == "dead":
         return
     self.db.health_status = "dead"
     self.db.container = True
     if self.location:
         self.location.msg_contents("{r%s has died.{n" % self.name)
     try:
         from commands.cmdsets import death
         cmds = death.DeathCmdSet
         if cmds.key not in [ob.key for ob in self.cmdset.all()]:
             self.cmdset.add(cmds, permanent=True)
     except Exception as err:
         print("<<ERROR>>: Error when importing death cmdset: %s" % err)
     from server.utils.arx_utils import inform_staff
     if not self.db.npc:
         inform_staff("{rDeath{n: Character {c%s{n has died." % self.key)
Example #22
0
 def do_pray(self):
     """Makes a prayer"""
     if not self.rhs:
         raise self.error_class(
             "You must specify who you are praying to and a prayer.")
     matches = InvocableEntity.objects.filter(
         Q(name__iexact=self.lhs)
         | Q(aliases__alias__iexact=self.lhs)).distinct()
     if not matches:
         raise self.error_class(
             f"No entity by the name {self.lhs}. Available: {InvocableEntity.get_public_names()}"
         )
     if len(matches) > 1:
         raise self.error_class(f"Too many matches for {self.lhs}.")
     entity = matches[0]
     # create prayer
     self.check_max_unanswered_prayers()
     self.check_max_prayers_this_week()
     Prayer.objects.create(character=self.caller,
                           entity=entity,
                           text=self.rhs)
     self.msg(f"You pray to {entity}.")
     inform_staff(f"New prayer by {self.caller} to {entity}: {self.rhs}")
Example #23
0
    def func(self):
        """Implement the command"""

        caller = self.caller
        args = self.args
        switches = self.switches
        apps = get_apps_manager(caller)
        if not apps:
            caller.msg(
                "Apps manager not found! Please inform the administrators.")
            return
        if not args and not switches:
            # '@app'
            # List all pending applications
            all_apps = apps.view_all_apps()
            if not all_apps:
                caller.msg("No applications found.")
                return
            # application[9] field is 'True' if pending/open
            pend_list = [app for app in all_apps.values() if app[9]]
            if not pend_list:
                caller.msg("No pending applications found.")
                return
            # app = [app_num, char_ob, email, date_submit, application_string,
            # gm_ob, date_answer, gm_notes, approval, pending]
            table = prettytable.PrettyTable(
                ["{w#", "{wCharacter", "{wEmail", "{wDate"])
            for app in pend_list:
                table.add_row(
                    [app[0], app[1].key.capitalize(), app[2], app[3]])
            caller.msg("{wApplications for Characters pending approval:\n%s" %
                       table)
            caller.msg("To view a particular application, @app <app number>")
            caller.msg("To view closed applications, use @app/old")
            return
        if args and not switches and not args.isdigit():
            # '@app <character>'
            # List all pending apps for a particular character
            apps_for_char = apps.view_all_apps_for_char(args)
            if not apps_for_char:
                caller.msg("No applications found.")
                return
            pend_list = [ob for ob in apps_for_char if ob[9]]
            if not pend_list:
                caller.msg("No pending applications found.")
                return
            # app = [app_num, char_ob, email, date_submit, application_string, gm_ob,
            # date_answer, gm_notes, approval, pending]
            table = prettytable.PrettyTable(
                ["{w#", "{wCharacter", "{wEmail", "{wDate"])
            for app in pend_list:
                table.add_row(
                    [app[0], app[1].key.capitalize(), app[2], app[3]])
            caller.msg("{wPending applications for %s:\n%s" % (args, table))
            caller.msg("To view a specific application, @app <app number>")
            return
        if args and args.isdigit() and (not switches or 'old' in switches):
            # '@app <#>
            # List a given ticket by
            app = apps.view_app(int(args))
            if not app:
                caller.msg("No application by that number for that character.")
                return
            email = app[2]
            alts = RosterEntry.objects.filter(current_account__email=email)
            caller.msg("{wCharacter:{n %s" % app[1].key.capitalize())
            caller.msg("{wApp Email:{n %s" % email)
            if alts:
                caller.msg("{wCurrent characters:{n %s" %
                           ", ".join(str(ob) for ob in alts))
            caller.msg("{wDate Submitted:{n %s" % app[3])
            caller.msg("{wApplication:{n %s" % app[4])
            if not app[9]:
                caller.msg("{wGM:{n %s" % app[5])
                caller.msg("{wDate Answered:{n %s" % app[6])
                caller.msg("{wGM Notes:{n %s" % app[7])
                caller.msg("{wApproved:{n %s" % app[8])
            return
        if 'approve' in switches:
            # @app/approve <#>=<notes>
            # mark a character as approved, then send an email to the player
            if not self.lhs or not self.rhs or not self.lhs.isdigit():
                caller.msg("Usage: @app/approve <#>=<notes>")
                return
            app = apps.view_app(int(self.lhs))
            if apps.close_app(int(self.lhs), caller, self.rhs, True):
                caller.msg("Application successfully approved.")
                if app and app[1]:
                    inform_staff(
                        "{w%s has approved %s's application.{n" %
                        (caller.key.capitalize(), app[1].key.capitalize()))
                try:

                    entry = RosterEntry.objects.get(
                        character__id=app[1].id,
                        player__id=app[1].player_ob.id)
                    active_roster = Roster.objects.get(name="Active")
                    entry.roster = active_roster
                    try:
                        account = PlayerAccount.objects.get(email=app[2])
                    except PlayerAccount.DoesNotExist:
                        account = PlayerAccount.objects.create(email=app[2])
                    entry.current_account = account
                    entry.save()
                    # clear cache so the character is moved correctly
                    entry.character.flush_from_cache(force=True)
                    entry.player.flush_from_cache(force=True)
                    from datetime import datetime
                    date = datetime.now()
                    if not AccountHistory.objects.filter(
                            entry=entry, account=account,
                            end_date__isnull=True).exists():
                        AccountHistory.objects.create(entry=entry,
                                                      account=account,
                                                      start_date=date)
                    # make sure all their Attributes are clean for new player
                    from server.utils.arx_utils import post_roster_cleanup, reset_to_default_channels
                    post_roster_cleanup(entry)
                    reset_to_default_channels(entry.player)
                    try:
                        from commands.cmdsets.starting_gear import setup_gear_for_char
                        if not entry.character:
                            raise ValueError(
                                "No character found for setup gear")
                        setup_gear_for_char(entry.character)
                    except ValueError:
                        traceback.print_exc()
                except (RosterEntry.DoesNotExist,
                        RosterEntry.MultipleObjectsReturned,
                        Roster.DoesNotExist, Roster.MultipleObjectsReturned,
                        AttributeError, ValueError, TypeError):
                    print(
                        "Error when attempting to mark closed application as active."
                    )
                    traceback.print_exc()
                try:
                    from world.dominion.setup_utils import setup_dom_for_char
                    setup_dom_for_char(app[1])
                except (ValueError, TypeError):
                    # will throw an exception if Dominion already set up
                    pass
                try:
                    bb = BBoard.objects.get(db_key__iexact="Roster Changes")
                    msg = "%s now has a new player and is on the active roster." % app[
                        1]
                    url = "http://play.arxmush.org" + app[1].get_absolute_url()
                    msg += "\nCharacter page: %s" % url
                    subject = "%s now active" % app[1]
                    bb.bb_post(self.caller,
                               msg,
                               subject=subject,
                               poster_name="Roster")
                except BBoard.DoesNotExist:
                    self.msg("Board not found for posting announcement")
                return
            else:
                caller.msg("Application closure failed.")
                return
        if 'delete' in switches or 'del' in switches:
            try:
                apps.delete_app(caller, int(self.args))
                return
            except (ValueError, TypeError):
                caller.msg("Could not delete an app for value of %s." %
                           self.args)
                return
        if 'deny' in switches:
            # @app/deny <#>=<notes>
            # mark a character as declined, then send an email to the player
            if not self.lhs or not self.rhs or not self.lhs.isdigit():
                caller.msg("Usage: @app/deny <#>=<notes>")
                return
            if apps.close_app(int(self.lhs), caller, self.rhs, False):
                caller.msg("Application successfully declined.")
                app = apps.view_app(int(self.lhs))
                if app and app[1]:
                    inform_staff(
                        "{w%s has declined %s's application.{n" %
                        (caller.key.capitalize(), app[1].key.capitalize()))
                return
            else:
                caller.msg("Application closure failed.")
                return
        if 'old' in switches:
            # List all non-pending applications
            all_apps = apps.view_all_apps()
            if not all_apps:
                caller.msg("No applications found.")
                return
            # application[9] field is 'True' if pending/open
            pend_list = [_app for _app in all_apps.values() if not _app[9]]
            pend_list.sort(key=lambda appl: appl[0])
            if not pend_list:
                caller.msg("No closed applications found.")
                return
            if not self.args:
                pend_list = pend_list[-20:]
            else:
                try:
                    pend_list = pend_list[-int(self.args):]
                except (TypeError, ValueError):
                    caller.msg("Could not display entries for that range.")
                    return
            # app = [app_num, char_ob, email, date_submit, application_string, gm_ob,
            #  date_answer, gm_notes, approval, pending]
            table = prettytable.PrettyTable(
                ["{w#", "{wCharacter", "{wEmail", "{wDate", "{wApproved"])
            for app in pend_list:
                table.add_row([
                    app[0], app[1].key.capitalize(), app[2], app[3][:9],
                    str(app[8])
                ])
            caller.msg("{wOld/Closed applications for characters:\n%s" % table)
            caller.msg("To view a particular application, @app <app number>")
            return
            pass
        if 'oldchar' in switches:
            apps_for_char = apps.view_all_apps_for_char(args)
            if not apps_for_char:
                caller.msg("No applications found.")
                return
            pend_list = [ob for ob in apps_for_char if not ob[9]]
            if not pend_list:
                caller.msg("No closed applications found.")
                return
            # app = [app_num, char_ob, email, date_submit, application_string, gm_ob,
            # date_answer, gm_notes, approval, pending]
            table = prettytable.PrettyTable([
                "{w#", "{wCharacter", "{wEmail", "{wDate", "{wGM", "{wApproved"
            ])
            for app in pend_list:
                table.add_row([
                    app[0], app[1].key.capitalize(), app[2], app[3][:9],
                    app[5].key,
                    str(app[8])
                ])
            caller.msg("{wOld/Closed applications for %s:\n%s" % (args, table))
            caller.msg("To view a particular application, @app <app number>")
            return
        if 'email' in switches:
            apps_for_email = apps.view_apps_for_email(args)
            if not apps_for_email:
                caller.msg("No applications found.")
                return
            table = prettytable.PrettyTable(
                ["{w#", "{wCharacter", "{wEmail", "{wDate"])
            for app in apps_for_email:
                table.add_row(
                    [app[0], app[1].key.capitalize(), app[2], app[3]])
            caller.msg("{wApplications for %s:\n%s" % (args, table))
            caller.msg("To view a particular application, @app <app number>")
            return
        if 'fixemail' in switches:
            try:
                if apps.fix_email(int(self.lhs), caller, self.rhs):
                    caller.msg("App email changed to %s." % self.rhs)
                return
            except (TypeError, ValueError, AttributeError):
                caller.msg("Must provide an app # and an email address.")
                return
        if 'resend' in switches:
            try:
                apps.resend(int(self.lhs), caller)
                return
            except (ValueError, TypeError, AttributeError):
                caller.msg("Must provide a valid app #.")
                return
        caller.msg("Invalid switch for @app.")
Example #24
0
    def func(self):
        """Implement the command"""
        caller = self.caller
        args = self.args
        switches = self.switches
        if not args and not switches or (set(switches)
                                         & set(self.query_open_switches)):
            # list all open tickets
            self.display_open_tickets()
            return
        if args and (not switches or 'old' in switches):
            # list individual ticket specified by args
            # ticket = [ticket_id, playob, request_string, date_submit, gm_ob, gm_notes, date_answer, optional_title]
            try:
                ticknum = int(args)
            except ValueError:
                self.display_open_tickets()
                caller.msg("Usage: Argument must be a ticket number.")
                return
            try:
                ticket = Ticket.objects.get(id=ticknum)
            except Ticket.DoesNotExist:
                self.display_open_tickets()
                caller.msg("No ticket found by that number.")
                return
            caller.msg(ticket.display())
            return
        if 'old' in switches and not args:
            # list closed tickets
            # closed & resolved tickets, assigned to current user
            tickets_closed_resolved = Ticket.objects.select_related(
                'queue').filter(
                    status__in=[Ticket.CLOSED_STATUS, Ticket.RESOLVED_STATUS
                                ]).filter(queue__in=self.queues_from_args)
            joblist = list(tickets_closed_resolved)
            if not joblist:
                caller.msg("No closed tickets.")
                return
            # get 20 most recent
            joblist = joblist[-20:]
            table = prettytable.PrettyTable(
                ["{w#", "{wPlayer", "{wRequest", "{wQueue"])
            for ticket in joblist:
                table.add_row([
                    str(ticket.id),
                    str(ticket.submitting_player),
                    str(ticket.title)[:20], ticket.queue.slug
                ])
            caller.msg("{wClosed Tickets:{n\n%s" % table)
            return
        if 'moreold' in switches:
            # list closed tickets
            tickets_closed_resolved = Ticket.objects.select_related(
                'queue').filter(
                    status__in=[Ticket.CLOSED_STATUS, Ticket.RESOLVED_STATUS]
                ).filter(queue__in=self.queues_from_args).filter(
                    id__gte=self.lhslist[0], id__lte=self.lhslist[1])
            joblist = list(tickets_closed_resolved)
            if not joblist:
                caller.msg("No closed tickets.")
                return
            table = prettytable.PrettyTable(
                ["{w#", "{wPlayer", "{wRequest", "{wQueue"])
            for ticket in joblist:
                table.add_row([
                    str(ticket.id),
                    str(ticket.submitting_player),
                    str(ticket.title)[:20], ticket.queue.slug
                ])
            caller.msg("{wClosed Tickets:{n\n%s" % table)
            return
        try:
            ticket = Ticket.objects.get(id=self.lhs)
        except (ValueError, Ticket.DoesNotExist):
            self.msg("No ticket found by that number.")
            return
        if 'close' in switches:
            # Closing a ticket. Check formatting first
            lhs = self.lhs
            rhs = self.rhs
            if not args or not lhs or not rhs:
                caller.msg("Usage: @job/close <#>=<GM Notes>")
                return
            try:
                numticket = int(lhs)
            except ValueError:
                caller.msg("Must give a number for the open ticket.")
                return
            if helpdesk_api.resolve_ticket(caller, numticket, rhs):
                caller.msg("Ticket successfully closed.")
                return
            else:
                caller.msg("Ticket closure failed for unknown reason.")
                return
        if 'assign' in switches:
            player = self.caller.search(self.rhs)
            if not player:
                return
            ticket.assigned_to = player
            ticket.save()
            inform_staff("{w%s has assigned ticket %s to %s." %
                         (caller, ticket.id, player))
            return
        if 'followup' in switches or 'update' in switches or "follow" in switches:
            lhs = self.lhs
            rhs = self.rhs
            if not lhs or not rhs:
                caller.msg("Usage: @job/followup <#>=<msg>")
                return
            if helpdesk_api.add_followup(caller, ticket, rhs):
                caller.msg("Followup added.")
                return
            caller.msg("Error in followup.")
            return

        if 'move' in switches:
            if not self.lhs or not self.rhs:
                self.msg("Usage: @job/move <#>=<msg>")
                return
            try:
                queue = Queue.objects.get(slug__iexact=self.rhs)
            except Queue.DoesNotExist:
                self.msg("Queue must be one of the following: %s" %
                         ", ".join(ob.slug for ob in Queue.objects.all()))
                return
            ticket.queue = queue
            ticket.save()
            self.msg("Ticket %s is now in queue %s." % (ticket.id, queue))
            return
        if 'delete' in switches or 'del' in switches:
            if ticket.queue.slug == "Story":
                self.msg(
                    "Cannot delete a storyaction. Please move it to a different queue first."
                )
                return
            ticket.delete()
            self.msg("Ticket #%s deleted." % self.lhs)
            return
        if 'priority' in switches:
            try:
                ticket.priority = int(self.rhs)
            except (TypeError, ValueError):
                self.msg("Must be a number.")
            ticket.save()
            self.msg("Ticket new priority is %s." % self.rhs)
            return
        if 'approve' in switches:
            pass
        if 'deny' in switches:
            pass
        caller.msg("Invalid switch for @job.")
Example #25
0
    def func(self):
        """Implement the command"""
        caller = self.caller
        args = self.args
        switches = self.switches
        old = "old" in switches
        if not args and not ('new' in switches or 'catchup' in switches):
            return list_bboards(caller, old)

        # first, "@bb <board #>" use case
        def board_check(reader, arguments):
            board_to_check = access_bboard(reader, arguments)
            if not board_to_check:
                return
            if not board_to_check.has_subscriber(reader):
                reader.msg("You are not yet a subscriber to {0}".format(
                    board_to_check.key))
                reader.msg("Use {w@bbsub{n to subscribe to it.")
                return
            list_messages(reader, board_to_check, arguments, old)

        if not switches or old and len(switches) == 1:
            arglist = args.split("/")
            if len(arglist) < 2:
                board_check(caller, args)
                return
            else:
                if arglist[1] == 'u':
                    switches.append('new')
                    # build arguments for bbnew command
                    args = " all=%s" % arglist[0]
                else:
                    switches.append('read')
        if 'new' in switches or 'catchup' in switches:
            if 'catchup' in switches:
                caller.execute_cmd("+bbnew/markread" + args)
                return
            caller.execute_cmd("+bbnew" + args)
            return
        # both post/read share board #
        arglist = args.split("/")

        board = access_bboard(caller, arglist[0])
        if not board:
            return

        if 'read' in switches:
            if len(arglist) < 2:
                board_check(caller, args)
                return
            postrange = [arg.strip() for arg in arglist[1].split("-")]
            if len(postrange) == 1:
                try:
                    post_num = int(arglist[1])
                except ValueError:
                    caller.msg("Invalid post number.")
                    return
                post = board.get_post(caller, post_num, old)
                if not post:
                    return
                board.read_post(caller, post, old)
                return
            num_read = 0
            try:
                for post_num in range(int(postrange[0]),
                                      int(postrange[1]) + 1):
                    try:
                        post = board.get_post(caller, int(post_num))
                        board.read_post(caller, post, old)
                        num_read += 1
                    except (TypeError, ValueError, AttributeError):
                        continue
            except (TypeError, ValueError, IndexError):
                caller.msg("Posts in the range must be numbers.")
                return
            if not num_read:
                caller.msg("No posts in range.")
            return
        if 'del' in switches or 'archive' in switches or 'sticky' in switches or 'delete' in switches:
            if "del" in switches or "delete" in switches:
                if board.tags.get(
                        "only_staff_delete"
                ) and not caller.check_permstring("builders"):
                    self.msg("Only builders may delete from that board.")
                    return
                switchname = "del"
                verb = "delete"
                method = "delete_post"
            elif "sticky" in switches:
                switchname = "sticky"
                verb = "sticky"
                method = "sticky_post"
            else:
                switchname = "archive"
                verb = "archive"
                method = "archive_post"
            if len(arglist) < 2:
                caller.msg("Usage: @bb/%s <board #>/<post #>" % switchname)
                return
            try:
                post_num = int(arglist[1])
            except ValueError:
                caller.msg("Invalid post number.")
                return
            post = board.get_post(caller, post_num, old)
            if not post:
                return
            if caller not in post.db_sender_accounts.all(
            ) and not board.access(caller, "edit"):
                caller.msg(
                    "You cannot %s someone else's post, only your own." % verb)
                return
            if getattr(board, method)(post):
                caller.msg("Post %sd" % verb)
                inform_staff("%s has %sd post %s on board %s." %
                             (caller, verb, post_num, board))
            else:
                caller.msg("Post %s failed for unknown reason." % verb)
            return
        if 'edit' in switches:
            lhs = self.lhs
            arglist = lhs.split("/")
            if len(arglist) < 2 or not self.rhs:
                self.msg("Usage: @bb/edit <board #>/<post #>")
                return
            try:
                post_num = int(arglist[1])
            except ValueError:
                self.msg("Invalid post number.")
                return
            board = access_bboard(caller, arglist[0], 'write')
            if not board:
                return
            post = board.get_post(caller, post_num)
            if not post:
                return
            if caller not in post.db_sender_accounts.all(
            ) and not board.access(caller, "edit"):
                caller.msg(
                    "You cannot edit someone else's post, only your own.")
                return
            if board.edit_post(self.caller, post, self.rhs):
                self.msg("Post edited.")
                inform_staff("%s has edited post %s on board %s." %
                             (caller, post_num, board))
            return
        if 'post' in switches:
            if not self.rhs:
                caller.msg(
                    "Usage: @bb/post <board #>/<subject> = <post message>")
                return
            lhs = self.lhs
            arglist = lhs.split("/")
            if len(arglist) < 2:
                subject = "No Subject"
            else:
                subject = arglist[1]
            board = access_bboard(caller, arglist[0], 'write')
            if not board:
                return
            board.bb_post(caller, self.rhs, subject)
Example #26
0
    def post_top_prestige(self):
        """Makes a board post of the top prestige earners this past week"""
        import random
        from world.dominion.models import PraiseOrCondemn
        changes = PraiseOrCondemn.objects.filter(week=self.db.week).exclude(
            target__organization_owner__secret=True)
        praises = defaultdict(list)
        condemns = defaultdict(list)
        total_values = {}
        for praise in changes.filter(value__gte=0):
            praises[praise.target].append(praise)
        for condemn in changes.filter(value__lt=0):
            condemns[condemn.target].append(condemn)
        for change in changes:
            current = total_values.get(change.target, 0)
            current += change.value
            total_values[change.target] = current

        board = BBoard.objects.get(db_key__iexact=PRESTIGE_BOARD_NAME)

        def get_total_from_list(entry_list):
            """Helper function to get total prestige amount from a list"""
            return sum(praise_ob.value for praise_ob in entry_list)

        sorted_praises = sorted(praises.items(),
                                key=lambda x: get_total_from_list(x[1]),
                                reverse=True)
        sorted_praises = sorted_praises[:20]
        table = EvTable("{wName{n",
                        "{wValue{n",
                        "{wMsg{n",
                        border="cells",
                        width=78)
        for tup in sorted_praises:
            praise_messages = [ob.message for ob in tup[1] if ob.message]
            selected_message = ""
            if praise_messages:
                selected_message = random.choice(praise_messages)
            table.add_row(
                str(tup[0]).capitalize()[:18], get_total_from_list(tup[1]),
                selected_message)
        table.reformat_column(0, width=18)
        table.reformat_column(1, width=10)
        table.reformat_column(2, width=50)
        prestige_msg = "{wMost Praised this week{n".center(72)
        prestige_msg = "%s\n%s" % (prestige_msg, str(table).lstrip())
        prestige_msg += "\n\n"
        try:
            # sort by our prestige change amount
            sorted_changes = sorted(total_values.items(),
                                    key=lambda x: abs(x[1]),
                                    reverse=True)
            sorted_changes = sorted_changes[:20]
            table = EvTable("{wName{n",
                            "{wPrestige Change Amount{n",
                            "{wPrestige Rank{n",
                            border="cells",
                            width=78)
            rank_order = list(
                AssetOwner.objects.filter(
                    player__player__roster__roster__name="Active").distinct())
            rank_order = sorted(rank_order,
                                key=lambda x: x.prestige,
                                reverse=True)
            for tup in sorted_changes:
                # get our prestige ranking compared to others
                owner = tup[0]
                try:
                    rank = rank_order.index(owner) + 1
                except ValueError:
                    # they rostered mid-week or whatever, skip them
                    continue
                # get the amount that our prestige has changed. add + for positive
                amt = tup[1]
                if amt > 0:
                    amt = "+%s" % amt
                table.add_row(owner, amt, rank)
            prestige_msg += "\n\n"
            prestige_msg += "{wTop Prestige Changes{n".center(72)
            prestige_msg = "%s\n%s" % (prestige_msg, str(table).lstrip())
        except (AttributeError, ValueError, TypeError):
            import traceback
            traceback.print_exc()
        board.bb_post(poster_obj=self,
                      msg=prestige_msg,
                      subject="Weekly Praises/Condemns",
                      poster_name="Prestige")
        inform_staff("Praises/condemns tally complete. Posted on %s." % board)
Example #27
0
    def func(self):
        """Execute command."""
        caller = self.caller
        ability = ("ability" in self.switches
                   or self.cmdstring == "@adjustability"
                   or self.cmdstring == "@adjustabilities")
        char = None
        if "reset" in self.switches or "refund" in self.switches:
            try:
                char = caller.search(self.lhs).char_ob
            except (AttributeError, ValueError, TypeError):
                caller.msg("No player by that name.")
                return
            if char.db.xp is None:
                char.db.xp = 0
            if "reset" in self.switches:
                try:
                    from commands.base_commands.guest import (
                        setup_voc,
                        XP_BONUS_BY_SRANK,
                    )

                    rhs = self.rhs.lower()
                    setup_voc(char, rhs)
                    char.db.vocation = rhs
                    total_xp = char.db.total_xp or 0
                    total_xp = int(total_xp)
                    xp = XP_BONUS_BY_SRANK[char.db.social_rank]
                    xp += total_xp
                    char.db.xp = xp
                    caller.msg(
                        "%s has had their skills and stats set up as a %s." %
                        (char, rhs))
                    return
                except (AttributeError, ValueError, TypeError, KeyError):
                    caller.msg("Could not set %s to %s vocation." %
                               (char, self.rhs))
                    return
        if "refund" in self.switches:
            if not ability:
                skill_history = char.db.skill_history or {}
                try:
                    current = len(char.db.skill_history[self.rhs])
                    skill_list = skill_history[self.rhs]
                    cost = skill_list.pop()
                    skill_history[self.rhs] = skill_list
                    char.db.skill_history = skill_history
                except (KeyError, IndexError, TypeError):
                    try:
                        current = char.traits.get_skill_value(self.rhs)
                    except KeyError:
                        caller.msg("No such skill.")
                        return
                    cost = stats_and_skills.cost_at_rank(
                        self.rhs, current - 1, current)
                if current <= 0:
                    caller.msg("That would give them a negative skill.")
                    return
                char.traits.set_skill_value(self.rhs, current - 1)
                char.db.xp += cost
            else:
                ability_history = char.db.ability_history or {}
                try:
                    current = char.traits.get_ability_value(self.rhs)
                    ability_list = ability_history[self.rhs]
                    cost = ability_list.pop()
                    ability_history[self.rhs] = ability_list
                    char.db.ability_history = ability_history
                except (KeyError, IndexError, TypeError):
                    current = char.traits.get_ability_value(self.rhs)
                    if not current:
                        caller.msg("No such ability.")
                        return
                    cost = stats_and_skills.cost_at_rank(
                        self.rhs, current - 1, current)
                if current <= 0:
                    caller.msg("That would give them a negative rating.")
                    return
                char.traits.set_ability_value(self.rhs, current - 1)
                char.db.xp += cost
            caller.msg("%s had %s reduced by 1 and was refunded %s xp." %
                       (char, self.rhs, cost))
            return
        try:
            player, skill = self.lhs.strip().split("/")
            rhs = int(self.rhs)
        except (AttributeError, ValueError, TypeError):
            caller.msg("Invalid syntax")
            return
        targ = caller.search(player)
        if not targ:
            caller.msg("No player found by that name.")
            return
        char = targ.char_ob
        if not char:
            caller.msg("No active character for %s." % targ)
            return
        if ability:
            char.traits.set_ability_value(skill, rhs)
        else:
            char.traits.set_skill_value(skill, rhs)
        if rhs <= 0:
            if ability:
                caller.msg("Removed ability %s from %s." % (skill, char))
            else:
                caller.msg("Removed skill %s from %s." % (skill, char))
        else:
            caller.msg("%s's %s set to %s." % (char, skill, rhs))
        if not caller.check_permstring("immortals"):
            inform_staff("%s set %s's %s skill to %s." %
                         (caller, char, skill, rhs))
Example #28
0
    def func(self):
        """Implement the command"""
        caller = self.caller
        if not self.crafter:
            self.crafter = caller
        crafter = self.crafter
        try:
            dompc = PlayerOrNpc.objects.get(player=caller.player)
            assets = AssetOwner.objects.get(player=dompc)
        except PlayerOrNpc.DoesNotExist:
            # dominion not set up on player
            dompc = setup_dom_for_char(caller)
            assets = dompc.assets
        except AssetOwner.DoesNotExist:
            # assets not initialized on player
            dompc = setup_dom_for_char(caller, create_dompc=False)
            assets = dompc.assets
        recipes = crafter.player_ob.Dominion.assets.recipes.all()
        if not self.args and not self.switches:
            # display recipes and any crafting project we have unfinished
            materials = assets.materials.all()
            caller.msg("{wAvailable recipes:{n %s" %
                       ", ".join(recipe.name for recipe in recipes))
            caller.msg("{wYour materials:{n %s" %
                       ", ".join(str(mat) for mat in materials))
            project = caller.db.crafting_project
            if project:
                self.display_project(project)
            return
        # start a crafting project
        if not self.switches or "craft" in self.switches:
            try:
                recipe = recipes.get(name__iexact=self.lhs)
            except CraftingRecipe.DoesNotExist:
                caller.msg("No recipe found by the name %s." % self.lhs)
                return
            try:
                self.get_recipe_price(recipe)
            except ValueError:
                caller.msg("That recipe does not have a price defined.")
                return
            # proj = [id, name, desc, adorns, forgery, translation]
            proj = [recipe.id, "", "", {}, {}, {}, ""]
            caller.db.crafting_project = proj
            stmsg = "You have" if caller == crafter else "%s has" % crafter
            caller.msg("{w%s started to craft:{n %s." % (stmsg, recipe.name))
            caller.msg(
                "{wTo finish it, use /finish after you gather the following:{n"
            )
            caller.msg(recipe.display_reqs(dompc))
            return
        if ("changename" in self.switches or "refine" in self.switches
                or "addadorn" in self.switches):
            targ = caller.search(self.lhs, location=caller)
            if not targ:
                return
            recipe = None
            try:
                recipe = targ.item_data.recipe
            except AttributeError:
                pass
            if not recipe:
                caller.msg("No recipe found for that item.")
                return
            if "changename" in self.switches:
                if not self.rhs:
                    self.msg("Usage: /changename <object>=<new name>")
                    return
                if not validate_name(self.rhs):
                    caller.msg("That is not a valid name.")
                    return
                if targ.tags.get("plot"):
                    self.msg("It cannot be renamed.")
                    return
                targ.aliases.clear()
                targ.name = self.rhs
                caller.msg("Changed name to %s." % targ)
                return
            # adding adorns post-creation
            if "addadorn" in self.switches:
                try:
                    material = self.rhslist[0]
                    amt = int(self.rhslist[1])
                    if amt < 1 and not caller.check_permstring("builders"):
                        raise ValueError
                except (IndexError, ValueError, TypeError):
                    caller.msg(
                        "Usage: /addadorn <object>=<adornment>,<amount>")
                    return
                if not recipe.allow_adorn:
                    caller.msg(
                        "This recipe does not allow for additional materials to be used."
                    )
                    return
                try:
                    mat = CraftingMaterialType.objects.get(
                        name__iexact=material)
                except CraftingMaterialType.DoesNotExist:
                    self.msg(
                        "Cannot use %s as it does not appear to be a crafting material."
                        % material)
                    return
                # if caller isn't a builder, check and consume their materials
                if not caller.check_permstring("builders"):
                    pmats = caller.player.Dominion.assets.materials
                    try:
                        pmat = pmats.get(type=mat)
                        if pmat.amount < amt:
                            caller.msg("You need %s of %s, and only have %s." %
                                       (amt, mat.name, pmat.amount))
                            return
                    except CraftingMaterials.DoesNotExist:
                        caller.msg("You do not have any of the material %s." %
                                   mat.name)
                        return
                    pmat.amount -= amt
                    pmat.save()
                targ.item_data.add_adorn(mat, amt)
                caller.msg("%s is now adorned with %s of the material %s." %
                           (targ, amt, mat))
                return
            if "refine" in self.switches:
                base_cost = recipe.value / 4
                caller.msg("The base cost of refining this recipe is %s." %
                           base_cost)
                try:
                    price = self.get_refine_price(base_cost)
                except ValueError:
                    caller.msg("Price for refining not set.")
                    return
                if price:
                    caller.msg("The additional price for refining is %s." %
                               price)
                action_points = 0
                invest = 0
                if self.rhs:
                    try:
                        invest = int(self.rhslist[0])
                        if len(self.rhslist) > 1:
                            action_points = int(self.rhslist[1])
                    except ValueError:
                        caller.msg(
                            "Amount of silver/action points to invest must be a number."
                        )
                        return
                    if invest < 0 or action_points < 0:
                        caller.msg("Amount must be positive.")
                        return
                if not recipe:
                    caller.msg(
                        "This is not a crafted object that can be refined.")
                    return
                if targ.item_data.quality_level and targ.item_data.quality_level >= 10:
                    caller.msg("This object can no longer be improved.")
                    return
                ability = get_ability_val(crafter, recipe)
                if ability < recipe.level:
                    err = "You lack" if crafter == caller else "%s lacks" % crafter
                    caller.msg(
                        "%s the skill required to attempt to improve this." %
                        err)
                    return
                if not self.check_max_invest(recipe, invest):
                    return
                cost = base_cost + invest + price
                # don't display a random number when they're prepping
                if caller.ndb.refine_targ != (targ, cost):
                    diffmod = get_difficulty_mod(recipe, invest)
                else:
                    diffmod = get_difficulty_mod(recipe, invest, action_points,
                                                 ability)
                # difficulty gets easier by 1 each time we attempt it
                attempts = targ.item_data.get_refine_attempts_for_character(
                    crafter)
                if attempts > 60:
                    attempts = 60
                diffmod += attempts
                if diffmod:
                    self.msg(
                        "Based on silver spent and previous attempts, the difficulty is adjusted by %s."
                        % diffmod)
                if caller.ndb.refine_targ != (targ, cost):
                    caller.ndb.refine_targ = (targ, cost)
                    caller.msg(
                        "The total cost would be {w%s{n. To confirm this, execute the command again."
                        % cost)
                    return
                if cost > caller.db.currency:
                    caller.msg("This would cost %s, and you only have %s." %
                               (cost, caller.db.currency))
                    return
                if action_points and not caller.player_ob.pay_action_points(
                        action_points):
                    self.msg("You do not have enough action points to refine.")
                    return
                # pay for it
                caller.pay_money(cost)
                self.pay_owner(
                    price,
                    "%s has refined '%s', a %s, at your shop and you earn %s silver."
                    % (caller, targ, recipe.name, price),
                )

                roll = do_crafting_roll(crafter,
                                        recipe,
                                        diffmod,
                                        diffmult=0.75,
                                        room=caller.location)
                quality = get_quality_lvl(roll, recipe.difficulty)
                old = targ.item_data.quality_level or 0
                attempts += 1
                targ.item_data.set_refine_attempts_for_character(
                    crafter, attempts)
                self.msg("The roll is %s, a quality level of %s." %
                         (roll, QUALITY_LEVELS[quality]))
                if quality <= old:
                    caller.msg(
                        "You failed to improve %s; the quality will remain %s."
                        % (targ, QUALITY_LEVELS[old]))
                    return
                caller.msg("New quality level is %s." %
                           QUALITY_LEVELS[quality])
                change_quality(targ, quality)
                return
        proj = caller.db.crafting_project
        if not proj:
            caller.msg("You have no crafting project.")
            return
        if "name" in self.switches:
            if not self.args:
                caller.msg("Name it what?")
                return
            if not validate_name(self.args):
                caller.msg("That is not a valid name.")
                return
            proj[1] = self.args
            caller.db.crafting_project = proj
            caller.msg("Name set to %s." % self.args)
            return
        if "desc" in self.switches:
            if not self.args:
                caller.msg("Describe it how?")
                return

            if not self.can_apply_templates(self.caller, self.args):
                return

            proj[2] = self.args
            caller.db.crafting_project = proj
            caller.msg("Desc set to:\n%s" % self.args)
            return
        if "abandon" in self.switches:
            caller.msg(
                "You have abandoned this crafting project. You may now start another."
            )
            caller.db.crafting_project = None
            return
        if "translated_text" in self.switches:
            if not (self.lhs and self.rhs):
                caller.msg("Usage: craft/translated_text <language>=<text>")
                return
            lhs = self.lhs.lower()
            if lhs not in self.caller.languages.known_languages:
                caller.msg("Nice try. You cannot speak %s." % self.lhs)
                return
            proj[5].update({lhs: self.rhs})
            caller.db.crafting_project = proj
            self.display_project(proj)
            return
        if "altdesc" in self.switches:
            if not self.args:
                caller.msg(
                    "Describe them how? This is only used for disguise recipes."
                )
                return
            proj[6] = self.args
            caller.msg(
                "This is only used for disguise recipes. Alternate description set to:\n%s"
                % self.args)
            return
        if "adorn" in self.switches:
            if not (self.lhs and self.rhs):
                caller.msg("Usage: craft/adorn <material>=<amount>")
                return
            try:
                mat = CraftingMaterialType.objects.get(name__iexact=self.lhs)
                amt = int(self.rhs)
            except CraftingMaterialType.DoesNotExist:
                caller.msg("No material named %s." % self.lhs)
                return
            except CraftingMaterialType.MultipleObjectsReturned:
                caller.msg("More than one match. Please be more specific.")
                return
            except (TypeError, ValueError):
                caller.msg("Amount must be a number.")
                return
            if amt < 1:
                caller.msg("Amount must be positive.")
                return
            recipe = CraftingRecipe.objects.get(id=proj[0])
            if not recipe.allow_adorn:
                caller.msg(
                    "This recipe does not allow for additional materials to be used."
                )
                return
            adorns = proj[3] or {}
            adorns[mat.id] = amt
            proj[3] = adorns
            caller.db.crafting_project = proj
            caller.msg(
                "Additional materials: %s" %
                ", ".join("%s: %s" %
                          (CraftingMaterialType.objects.get(id=mat).name, amt)
                          for mat, amt in adorns.items()))
            return
        if "forgery" in self.switches:
            self.msg("Temporarily disabled until I have time to revamp this.")
            return
        if "preview" in self.switches:
            if self.args:
                viewer = self.caller.player.search(self.args)
                if not viewer:
                    return
                viewer.msg(
                    "{c%s{n is sharing a preview of their crafting project with you."
                    % self.caller)
                self.msg(
                    "You share a preview of your crafting project with %s." %
                    viewer)
            else:
                viewer = self.caller.player
            name = proj[1] or "[No Name Yet]"
            viewer.msg("{wPreview of {n%s {wdesc:{n\n%s" % (name, proj[2]))
            return
        # do rolls for our crafting. determine quality level, handle forgery stuff
        if "finish" in self.switches:
            if not proj[1]:
                caller.msg("You must give it a name first.")
                return
            if not proj[2]:
                caller.msg("You must write a description first.")
                return
            invest = 0
            action_points = 0
            if self.lhs:
                try:
                    invest = int(self.lhslist[0])
                    if len(self.lhslist) > 1:
                        action_points = int(self.lhslist[1])
                except ValueError:
                    caller.msg(
                        "Silver/Action Points to invest must be a number.")
                    return
                if invest < 0 or action_points < 0:
                    caller.msg(
                        "Silver/Action Points cannot be a negative number.")
                    return
            # first, check if we have all the materials required
            mats = {}
            try:
                recipe = recipes.get(id=proj[0])
            except CraftingRecipe.DoesNotExist:
                caller.msg("You lack the ability to finish that recipe.")
                return
            if not self.check_max_invest(recipe, invest):
                return
            if recipe.type == "disguise":
                if not proj[6]:
                    caller.msg(
                        "This kind of item requires craft/altdesc before it can be finished."
                    )
                    return
            for mat in recipe.materials.all():
                mats[mat.id] = mats.get(mat.id, 0) + mat.amount
            for adorn in proj[3]:
                mats[adorn] = mats.get(adorn, 0) + proj[3][adorn]
            # replace with forgeries
            for rep in proj[4].keys():
                # rep is ID to replace
                forg = proj[4][rep]
                if rep in mats:
                    amt = mats[rep]
                    del mats[rep]
                    mats[forg] = amt
            # check silver cost
            try:
                price = self.get_recipe_price(recipe)
            except ValueError:
                caller.msg("That recipe does not have a price defined.")
                return
            cost = recipe.additional_cost + invest + price
            if cost < 0 or price < 0:
                errmsg = "For %s at %s, recipe %s, cost %s, price %s" % (
                    caller,
                    caller.location,
                    recipe.id,
                    cost,
                    price,
                )
                raise ValueError(errmsg)
            if not caller.check_permstring("builders"):
                if caller.db.currency < cost:
                    caller.msg(
                        "The recipe costs %s on its own, and you are trying to spend an additional %s."
                        % (recipe.additional_cost, invest))
                    if price:
                        caller.msg(
                            "The additional price charged by the crafter for this recipe is %s."
                            % price)
                    caller.msg("You need %s silver total, and have only %s." %
                               (cost, caller.db.currency))
                    return
                pmats = caller.player.Dominion.assets.materials
                # add up the total cost of the materials we're using for later
                realvalue = 0
                for mat in mats:
                    try:
                        c_mat = CraftingMaterialType.objects.get(id=mat)
                    except CraftingMaterialType.DoesNotExist:
                        inform_staff(
                            "Attempted to craft using material %s which does not exist."
                            % mat)
                        self.msg(
                            "One of the materials required no longer seems to exist. Informing staff."
                        )
                        return
                    try:
                        pmat = pmats.get(type=c_mat)
                        if pmat.amount < mats[mat]:
                            caller.msg("You need %s of %s, and only have %s." %
                                       (mats[mat], c_mat.name, pmat.amount))
                            return
                        realvalue += c_mat.value * mats[mat]
                    except CraftingMaterials.DoesNotExist:
                        caller.msg("You do not have any of the material %s." %
                                   c_mat.name)
                        return
                # check if they have enough action points
                if not caller.player_ob.pay_action_points(2 + action_points):
                    self.msg(
                        "You do not have enough action points left to craft that."
                    )
                    return
                # pay the money
                caller.pay_money(cost)
                # we're still here, so we have enough materials. spend em all
                for mat in mats:
                    cmat = CraftingMaterialType.objects.get(id=mat)
                    pmat = pmats.get(type=cmat)
                    pmat.amount -= mats[mat]
                    pmat.save()
            else:
                realvalue = recipe.value
            # determine difficulty modifier if we tossed in more money
            ability = get_ability_val(crafter, recipe)
            diffmod = get_difficulty_mod(recipe, invest, action_points,
                                         ability)
            # do crafting roll
            roll = do_crafting_roll(crafter,
                                    recipe,
                                    diffmod,
                                    room=caller.location)
            # get type from recipe
            otype = recipe.type
            # create object
            if otype == "wieldable":
                obj, quality = create_weapon(recipe, roll, proj, caller)
            elif otype == "wearable":
                obj, quality = create_wearable(recipe, roll, proj, caller)
            elif otype == "place":
                obj, quality = create_place(recipe, roll, proj, caller)
            elif otype == "book":
                obj, quality = create_book(recipe, roll, proj, caller)
            elif otype == "container":
                obj, quality = create_container(recipe, roll, proj, caller)
            elif otype == "decorative_weapon":
                obj, quality = create_decorative_weapon(
                    recipe, roll, proj, caller)
            elif otype == "wearable_container":
                obj, quality = create_wearable_container(
                    recipe, roll, proj, caller)
            elif otype == "perfume":
                obj, quality = create_consumable(recipe, roll, proj, caller,
                                                 PERFUME)
            elif otype == "disguise":
                obj, quality = create_mask(recipe, roll, proj, caller, proj[6])
            else:
                obj, quality = create_generic(recipe, roll, proj, caller)
            # finish stuff universal to all crafted objects
            obj.desc = proj[2]
            obj.save()

            self.apply_templates_to(obj)

            obj.item_data.materials = mats
            obj.item_data.recipe = recipe.id
            obj.item_data.adorns = proj[3]
            obj.item_data.crafted_by = crafter
            obj.item_data.size = int(recipe.resultsdict.get("volume", 0))
            self.pay_owner(
                price,
                "%s has crafted '%s', a %s, at your shop and you earn %s silver."
                % (caller, obj, recipe.name, price),
            )
            try:
                if proj[5]:
                    obj.item_data.translation = proj[5]
            except IndexError:
                pass
            cnoun = "You" if caller == crafter else crafter
            caller.msg("%s created %s." % (cnoun, obj.name))
            quality = QUALITY_LEVELS[quality]
            caller.msg("It is of %s quality." % quality)
            caller.db.crafting_project = None
            return
Example #29
0
 def func(self):
     """
     Allows the character to check their xp, and spend it if they use
     the /spend switch and meet the requirements.
     """
     caller = self.caller
     dompc = None
     resource = None
     set_specialization = False
     spec_warning = False
     if self.cmdstring == "learn":
         self.switches.append("spend")
     if not self.args:
         # Just display our xp
         self.display_traits()
         return
     if "transfer" in self.switches:
         self.transfer_xp()
         return
     args = self.args.lower()
     # get cost already factors in if we have a trainer, so no need to check
     if args in Trait.get_valid_stat_names():
         cost = stats_and_skills.get_stat_cost(caller, args)
         current = caller.traits.get_stat_value(args)
         if not caller.traits.check_stat_can_be_raised(args):
             caller.msg("%s is already at its maximum." % args)
             return
         stype = "stat"
     elif args in Trait.get_valid_skill_names():
         current = caller.traits.get_skill_value(args)
         if current >= 6:
             caller.msg("%s is already at its maximum." % args)
             return
         if (current >= 5 and
                 stats_and_skills.get_skill_cost_increase(caller) <= -1.0):
             caller.msg(
                 "You cannot buy a legendary skill while you still have catchup xp remaining."
             )
             return
         cost = stats_and_skills.get_skill_cost(caller, args)
         stype = "skill"
     elif args in stats_and_skills.DOM_SKILLS:
         try:
             dompc = caller.player.Dominion
             current = getattr(dompc, args)
             resource = stats_and_skills.get_dom_resource(args)
             if current >= 10:
                 caller.msg("%s is already at its maximum." % args)
                 return
             cost = stats_and_skills.get_dom_cost(caller, args)
             stype = "dom"
         except AttributeError:
             caller.msg("Dominion object not found.")
             return
     elif args in Trait.get_valid_ability_names():
         # if we don't have it, determine if we can learn it
         current = caller.traits.get_ability_value(args)
         if not current:
             if args in Trait.get_valid_ability_names(Trait.CRAFTING):
                 # check if we have valid skill:
                 if args == "tailor" and "sewing" not in caller.traits.skills:
                     caller.msg("You must have sewing to be a tailor.")
                     return
                 if (args == "weaponsmith" or args == "armorsmith"
                     ) and "smithing" not in caller.traits.skills:
                     caller.msg("You must have smithing to be a %s." % args)
                     return
                 if args == "apothecary" and "alchemy" not in caller.traits.skills:
                     caller.msg(
                         "You must have alchemy to be an apothecary.")
                     return
                 if (args == "leatherworker"
                         and "tanning" not in caller.traits.skills):
                     caller.msg(
                         "You must have tanning to be a leatherworker.")
                     return
                 if (args == "carpenter"
                         and "woodworking" not in caller.traits.skills):
                     caller.msg(
                         "You must have woodworking to be a carpenter.")
                     return
                 if args == "jeweler" and "smithing" not in caller.traits.skills:
                     caller.msg("You must have smithing to be a jeweler.")
                     return
                 spec_warning = True
             elif not caller.check_permstring(args):
                 caller.msg("You do not have permission to learn %s." %
                            args)
                 return
             else:
                 spec_warning = False
         if current >= 6:
             caller.msg("%s is already at its maximum." % args)
             return
         if args in Trait.get_valid_ability_names(Trait.CRAFTING):
             spec_warning = True
         if current == 5:
             if any(key for key, value in caller.traits.abilities.items()
                    if key in Trait.get_valid_ability_names(Trait.CRAFTING)
                    and value >= 6):
                 caller.msg(
                     "You have already chosen a crafting specialization.")
                 return
             else:
                 set_specialization = True
                 spec_warning = False
         stype = "ability"
         cost = stats_and_skills.get_ability_cost(caller, args)
     else:
         caller.msg("'%s' wasn't identified as a stat, ability, or skill." %
                    self.args)
         return
     if "cost" in self.switches:
         caller.msg("Cost for %s: %s" % (self.args, cost))
         return
     if "spend" in self.switches:
         # ap_cost = 5 * (current + 1)
         # if not self.player.pay_action_points(ap_cost):
         #     self.msg("You do not have enough action points to spend xp on that.")
         #     return
         if stype == "dom":
             if cost > getattr(dompc.assets, resource):
                 msg = "Unable to buy influence in %s. The cost is %s, " % (
                     args,
                     cost,
                 )
                 msg += "and you have %s %s resources available." % (
                     getattr(dompc.assets, resource),
                     resource,
                 )
                 caller.msg(msg)
                 return
         elif cost > caller.db.xp:
             caller.msg(
                 "Unable to raise %s. The cost is %s, and you have %s xp." %
                 (args, cost, caller.db.xp))
             return
         if stype == "stat":
             caller.adjust_xp(-cost)
             caller.traits.adjust_stat(args)
             caller.msg("You have increased your %s to %s." %
                        (args, current + 1))
             return
         if stype == "skill":
             caller.adjust_xp(-cost)
             caller.traits.adjust_skill(args)
             skill_history = caller.db.skill_history or {}
             spent_list = skill_history.get(args, [])
             spent_list.append(cost)
             skill_history[args] = spent_list
             caller.db.skill_history = skill_history
             caller.msg("You have increased your %s to %s." %
                        (args, current + 1))
             if current + 1 == 6:  # legendary rating
                 inform_staff("%s has bought a rank 6 of %s." %
                              (caller, args))
             return
         if stype == "ability":
             if set_specialization:
                 caller.msg("You have set your primary ability to be %s." %
                            args)
             if spec_warning:
                 caller.msg(
                     "{wNote: The first crafting ability raised to 6 will be your specialization.{n"
                 )
             caller.adjust_xp(-cost)
             caller.traits.adjust_ability(args)
             ability_history = caller.db.ability_history or {}
             spent_list = ability_history.get(args, [])
             spent_list.append(cost)
             ability_history[args] = spent_list
             caller.db.ability_history = ability_history
             caller.msg("You have increased your %s to %s." %
                        (args, current + 1))
             return
         if stype == "dom":
             # charge them influence
             setattr(dompc.assets, resource,
                     getattr(dompc.assets, resource) - cost)
             caller.traits.adjust_dom(args)
             caller.msg(
                 "You have increased your %s influence for a cost of %s %s resources."
                 % (args, resource, cost))
             caller.refresh_from_db()
             return
         return
     # invalid or no switch + arguments
     caller.msg("Usage: xp/spend <stat, ability or skill>")