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))
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))
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) )
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)
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
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)
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.")
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.")
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
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))
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
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.")
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
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
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)
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.")
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
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))
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))
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)
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)
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}")
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.")
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.")
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)
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)
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))
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
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>")