def model_outfit_for_fashion(self, org): """ Modeling Spine. If there are items in this outfit that can be modeled & action points are paid, then snapshots are created for each and a sum of all their fame is returned. """ from world.fashion.mixins import FashionableMixins if self.modeled: raise FashionError("%s has already been modeled." % self) if not self.is_carried or not self.is_equipped: raise FashionError( "Outfit must be equipped before trying to model it.") valid_items = self.check_outfit_fashion_ready() ap_cost = len(valid_items) * FashionableMixins.fashion_ap_cost if not self.owner.player.pay_action_points(ap_cost): raise FashionError( "It costs %d AP to model %s; you do not have enough energy." % (ap_cost, self)) outfit_fame = 0 for item in valid_items: outfit_fame += item.model_for_fashion(self.owner.player, org, outfit=self) return min(outfit_fame, self.FAME_CAP)
def check_recency(self, org=None): """Raises an error if we've modelled too recently""" from evennia.scripts.models import ScriptDB maximum = ServerConfig.objects.conf(key="MAX_FASHION_PER_WEEK") if not maximum: return try: last_cron = ScriptDB.objects.get( db_key="Weekly Update" ).db.run_date - timedelta(days=7) except (ScriptDB.DoesNotExist, ValueError, TypeError): last_cron = datetime.now() - timedelta(days=7) qs = self.caller.dompc.fashion_snapshots if qs.filter(db_date_created__gte=last_cron).count() >= maximum: raise FashionError( "You may only model up to %s items a week before the public tires of you." % maximum ) if org: if qs.filter(db_date_created__gte=last_cron, org=org): raise FashionError( "You have displayed fashion too recently for %s to bring them more acclaim." % org )
def check_fashion_ready(self): """Raises FashionError if the object is not ready to be modeled.""" if self.modeled_by: raise FashionError("%s has already been used to model fashion." % self) if not self.crafted_by_mortals: raise FashionError( "%s was wrought by no mortal hand, and from it no mortal fame can be earned." % self) return True
def display_item_snapshots(self): """displays snapshots""" from evennia.objects.models import ObjectDB try: item = ObjectDB.objects.get(id=self.args) except ObjectDB.DoesNotExist: raise FashionError("No object found for ID %s." % self.args) snapshots = item.fashion_snapshots.all() if not snapshots: raise FashionError("No snapshot exists for %s." % item) self.msg("%s snapshot: %s" % (item, ", ".join(ob.id + " by " + ob.fashion_model for ob in snapshots)))
def func(self): """Execute command""" try: if not self.args or not self.args.isdigit(): raise FashionError("Requires an ID #.") elif not self.switches: self.display_item_snapshots() elif "delete" in self.switches: self.reverse_snapshot(self.args) else: raise FashionError("Invalid Switch") except FashionError as err: self.msg(err)
def get_caller_outfit_from_args(caller, args): not_found = "'%s' not found in your collection of outfits." % args if not args: raise FashionError("Requires an outfit's name.") try: return caller.player_ob.Dominion.fashion_outfits.get(name__icontains=args) except Outfit.MultipleObjectsReturned: not_found = "'%s' refers to more than one outfit; please be more specific." % args try: return caller.player_ob.Dominion.fashion_outfits.get(name__iexact=args) except (Outfit.MultipleObjectsReturned, Outfit.DoesNotExist): raise FashionError(not_found) except Outfit.DoesNotExist: raise FashionError(not_found)
def model_item(self): """Models an item to earn fame.""" if not self.rhs: raise FashionError("Please specify <item>=<organization>") item = self.caller.search(self.lhs, location=self.caller) org = Organization.objects.get_public_org(self.rhs, self.caller) if not item or not org: return player = self.caller.player try: fame = item.model_for_fashion(player, org) except AttributeError: raise FashionError("%s is not an item you can model for fashion." % item) else: self.emit_modeling_result(item, org, fame)
def check_outfit_fashion_ready(self): """ Checks each item for model-readiness. If any are not, an exception is raised showing reasons for each. User may repeat the command to model the remaining items, if any exist. Returns a set of valid items. """ valid_items = set(self.fashion_items.all()) skipped_items = set() skipped_msg = "|wPieces of this outfit cannot be modeled:|n" for item in valid_items: try: item.check_fashion_ready() except FashionError as err: skipped_msg += "\n- " + str(err) skipped_items.add(item) valid_items = valid_items.difference(skipped_items) if skipped_items and self.owner.player.ndb.outfit_model_prompt != str( self): skipped_msg += "\n|y" if valid_items: self.owner.player.ndb.outfit_model_prompt = str(self) skipped_msg += "Repeat command to model the %d remaining item(s)" % len( valid_items) else: skipped_msg += "No valid items remain! Try modeling a different outfit" raise FashionError(skipped_msg + ".|n") self.owner.player.ndb.outfit_model_prompt = None return valid_items
def check_fashion_ready(self): super(Wearable, self).check_fashion_ready() if not self.is_worn: from world.fashion.exceptions import FashionError raise FashionError( "Please wear %s before trying to model it as fashion." % self) return True
def view_outfits(self, archived=False): """Views elements of one outfit as table, or a table of outfits.""" if self.args: outfit = get_caller_outfit_from_args(self.caller, self.args) msg = outfit.table_display else: outfits = self.caller.dompc.fashion_outfits.filter( archived=archived ).order_by("name") if len(outfits) < 1: status = "archived " if archived else "" alt = ( "regular 'outfits'" if archived else "creating one, or 'outfits/archives'" ) raise FashionError( "No %soutfits to display! Try %s instead." % (status, alt) ) outfit_header = "%sOutfit" % ("Archived " if archived else "") # TODO: event & vote columns table = PrettyTable(("Created", outfit_header, "Appraisal/Buzz")) for outfit in outfits: date = outfit.db_date_created.strftime("%Y/%m/%d") table.add_row((date, outfit.name, outfit.appraisal_or_buzz)) msg = str(table) self.msg(msg)
def check_audience(self): characters = [] for obj in self.caller.location.contents: if obj.is_typeclass("typeclasses.characters.Character") and not obj == self.caller: characters.append(obj) if len(characters) == 0: raise FashionError("There doesn't seem to be anyone here to model for!")
def check_fashion_ready(self): from world.fashion.mixins import FashionableMixins FashionableMixins.check_fashion_ready(self) if not (self.is_wielded or self.is_worn): from world.fashion.exceptions import FashionError verb = "wear" if self.decorative else "sheathe" raise FashionError("Please wield or %s %s before trying to model it as fashion." % (verb, self)) return True
def view_leaderboards(self): """Views table of fashion leaders""" from django.db.models import Sum, Count, Avg, F, IntegerField pretty_headers = ["Fashion Model", "Fame", "Items", "Avg Item Fame"] # default for top 20 models def get_queryset(manager, group_by_string, fame_divisor): """Teeny helper function for getting annotated queryset""" return (manager.values_list(group_by_string).annotate( total_fame=Sum(F('fame') / fame_divisor)).annotate( Count('id')).annotate(avg=Avg( F('fame') / fame_divisor, output_field=IntegerField())).order_by('-total_fame')) if "designer" in self.switches or "designers" in self.switches: if self.args: designer = self.caller.player.search(self.args) if not designer: return pretty_headers[0] = "%s Model" % designer designer = designer.Dominion qs = get_queryset(designer.designer_snapshots, 'fashion_model__player__username', Snapshot.DESIGNER_FAME_DIVISOR) else: pretty_headers[0] = "Designer" qs = get_queryset(Snapshot.objects, 'designer__player__username', Snapshot.DESIGNER_FAME_DIVISOR) elif "org" in self.switches or "orgs" in self.switches: if self.args: org = Organization.objects.get_public_org( self.args, self.caller) if not org: return pretty_headers[0] = "%s Model" % org qs = get_queryset(org.fashion_snapshots, 'fashion_model__player__username', Snapshot.ORG_FAME_DIVISOR) else: pretty_headers[0] = "Organization" qs = get_queryset(Snapshot.objects, 'org__name', Snapshot.ORG_FAME_DIVISOR) else: # Models by fame qs = get_queryset(Snapshot.objects, 'fashion_model__player__username', 1) qs = qs[:20] if "all" not in self.switches else qs if not qs: raise FashionError("Nothing was found.") table = PrettyTable(pretty_headers) for q in qs: # for lowercase names, we'll capitalize them if q[0] == q[0].lower(): q = list(q) q[0] = q[0].capitalize() table.add_row(q) self.msg(str(table))
def reverse_snapshot(self, snapshot_id): """reverses snapshots""" try: snapshot = Snapshot.objects.get(id=snapshot_id) except Snapshot.DoesNotExist: raise FashionError("No snapshot with ID# %s." % snapshot_id) snapshot.reverse_snapshot() self.msg("Snapshot #%s fame/ap has been reversed. Deleting it." % snapshot.id) snapshot.delete()
def model_outfit(self): """Models an outfit to earn fame.""" if not self.rhs: raise FashionError("Please specify <outfit>=<organization>") outfit = get_caller_outfit_from_args(self.caller, self.lhs) org = Organization.objects.get_public_org(self.rhs, self.caller) if not outfit or not org: return fame = outfit.model_outfit_for_fashion(org) self.emit_modeling_result(outfit, org, fame)
def create_outfit(self): """Create outfit object, add equipment to it, then display result.""" if not self.args: raise FashionError("Cannot create your shiny new outfit without a name.") others = self.caller.player_ob.Dominion.fashion_outfits.filter(name__iexact=self.args) if others.exists(): raise FashionError("You own an outfit named '%s' already." % self.args) worn = list(self.caller.worn) weapons = list(self.caller.wielded) + list(self.caller.sheathed) if not worn and not weapons: raise FashionError("Emperor %s's New Clothes? Put something on and try again." % self.caller.player) outfit = Outfit.objects.create(name=self.args, owner=self.caller.dompc) for weapon in weapons: slot = "primary weapon" if weapon.is_wielded else "sheathed weapon" outfit.add_fashion_item(item=weapon, slot=slot) for item in worn: outfit.add_fashion_item(item=item) msg = "Created " + outfit.list_display self.msg(msg)
def func(self): """Execute model command""" try: if self.args and not self.switches: self.model_item() elif "outfit" in self.switches: self.model_outfit() elif not self.switches or self.check_switches(self.leaderboard_switches): self.view_leaderboards() else: raise FashionError("Invalid Switch") except FashionError as err: self.msg(err)
def model_for_fashion(self, player, org, outfit=None): """ Our spine: Checks the item's availability as well as the model's. Makes snapshot object and has it calculate fame. Then fame is awarded and a record of it made. """ self.check_fashion_ready() if not outfit and not player.pay_action_points(self.fashion_ap_cost): msg = "It costs %d AP to model %s; you do not have enough energy." % ( self.fashion_ap_cost, self) raise FashionError(msg) snapshot = FashionSnapshot.objects.create( fashion_model=player.Dominion, fashion_item=self, org=org, designer=self.designer.Dominion, outfit=outfit) snapshot.roll_for_fame() snapshot.apply_fame() snapshot.inform_fashion_clients() return snapshot.fame
def func(self): try: def get_outfit(): return get_caller_outfit_from_args(self.caller, self.args) if self.check_switches(self.archive_switches): if self.args: self.archive_or_restore_outfit(get_outfit()) else: self.view_outfits(archived=True) elif "create" in self.switches: self.create_outfit() elif "delete" in self.switches: self.delete_outfit(get_outfit()) elif not self.switches: self.view_outfits() else: raise FashionError("Invalid Switch") except FashionError as err: self.msg(err)