def odds_against(self, battle): sword_strength = 0 bow_strength = 0 bashing_strength = 0 if self.sword: sword_strength = self.stat_bonus(Stat.objects.get(name="Swordfighting")) if CharacterStat.objects.filter(character=self, stat__name="Swordfighting"): sword_strength += level_from_value( CharacterStat.objects.get(character=self, stat__name="Swordfighting").value ) if self.bow: bow_strength = self.stat_bonus(Stat.objects.get(name="Archery")) if CharacterStat.objects.filter(character=self, stat__name="Archery"): bow_strength += level_from_value(CharacterStat.objects.get(character=self, stat__name="Archery").value) # Unlike bows and swords, we can use bashing even without an item equipped. if self.bashing: bashing_strength += self.bashing.amount if CharacterStat.objects.filter(character=self, stat__name="Bashing"): bashing_strength += level_from_value(CharacterStat.objects.get(character=self, stat__name="Bashing").value) if battle.enemy == Battle.ENEMY_RANGED: sword_strength = sword_strength - (5 + 0.1 * sword_strength) bashing_strength = bashing_strength + (5 + 0.1 * bashing_strength) elif battle.enemy == Battle.ENEMY_BASHING: sword_strength = sword_strength + (5 + 0.1 * sword_strength) bow_strength = bow_strength - (5 + 0.1 * bow_strength) else: bow_strength = bow_strength + (5 + 0.1 * bow_strength) bashing_strength = bashing_strength - (5 + 0.1 * bashing_strength) best_strength = 0 weapon = None if bow_strength >= sword_strength and bow_strength >= bashing_strength: best_strength = bow_strength weapon = self.bow elif sword_strength >= bow_strength and sword_strength >= bashing_strength: best_strength = bow_strength weapon = self.sword else: best_strength = bashing_strength weapon = self.bashing # Phew! Now, calculate the delta! odds = 0.5 + 0.05 * (best_strength - battle.strength) # Can play around with this, but I think there's always a 5% chance of success or failure. (Nice D20 odds.) if odds < 0.05: odds = 0.05 elif odds > 0.95: odds = 0.95 return {"odds": odds, "weapon": weapon}
def valid_for_stat_pre_reqs(character, pre_reqs, enforceMax): if pre_reqs: try: for pre_req in pre_reqs: if pre_req.minimum > 0: character_stat = CharacterStat.objects.get(character=character.pk, stat=pre_req.stat) level = level_from_value(character_stat.value) level += character.stat_bonus(character_stat.stat) # print "For stat " + character_stat.stat.name + " comparing " + str(level) + ":" + str(level_from_value(level)) + " to " + str(pre_req.minimum) if level < pre_req.minimum: return False elif enforceMax and level_from_value(character_stat.value) > pre_req.maximum: return False except CharacterStat.DoesNotExist: return False return True
def max_health(self): amount = 0 stats = CharacterStat.objects.filter(character=self, stat__type=Stat.TYPE_SKILL).order_by("-value") if stats: best_stat = stats[0] amount = level_from_value(best_stat.value) if amount < 10: amount = 10 return amount
def character(request): current_character = Character.objects.get(player=request.user.id) titles = CharacterTitle.objects.filter(character = current_character) skills = CharacterStat.objects.filter(character = current_character, stat__type= Stat.TYPE_SKILL, value__gte = 10) for skill in skills: skill.value = level_from_value(skill.value) + current_character.stat_bonus(skill.stat) plots = CharacterPlot.objects.filter(character = current_character, plot__visible = True, plot__achievement = False ) plot_descriptions = list() for plot in plots: #print "Looking at " + plot.__unicode__() + " " + str(plot.pk) + " value = " + str(plot.value) #for arg in PlotDescription.objects.filter(plot = plot.plot.pk): # print "Candidate " + " " + str(arg.pk) + ":" + arg.__unicode__() + ": " + str(arg.value) if PlotDescription.objects.filter(plot = plot.plot.pk, value = plot.value): #print "Got a match." plot_descriptions.append(PlotDescription.objects.get(plot=plot.plot, value=plot.value)) achievements = list(CharacterPlot.objects.filter(character = current_character, plot__achievement = True)) achievements.reverse() items = CharacterItem.objects.filter(character = current_character, quantity__gt = 0) fame = 0 if CharacterStat.objects.filter(character = current_character, stat__type= Stat.TYPE_FAME): fame = level_from_value(CharacterStat.objects.filter(character = current_character, stat__type= Stat.TYPE_FAME)[0].value) esteems = CharacterStat.objects.filter(character = current_character, stat__type = Stat.TYPE_ESTEEM) for esteem in esteems: esteem.value = level_from_value(esteem.value) if current_character.gender == Character.GENDER_MALE: title = "Mr." else: title = "Ms." swords = CharacterItem.objects.filter(character = current_character, item__equipment__type = Equipment.TYPE_SWORD) bashing = CharacterItem.objects.filter(character = current_character, item__equipment__type = Equipment.TYPE_BASHING) bows = CharacterItem.objects.filter(character = current_character, item__equipment__type = Equipment.TYPE_BOW) feet = CharacterItem.objects.filter(character = current_character, item__equipment__type = Equipment.TYPE_FEET) cloaks = CharacterItem.objects.filter(character = current_character, item__equipment__type = Equipment.TYPE_CLOAK) clothes = CharacterItem.objects.filter(character = current_character, item__equipment__type = Equipment.TYPE_CLOTHES) gloves = CharacterItem.objects.filter(character = current_character, item__equipment__type = Equipment.TYPE_GLOVES) rings = CharacterItem.objects.filter(character = current_character, item__equipment__type = Equipment.TYPE_RING) neck = CharacterItem.objects.filter(character = current_character, item__equipment__type = Equipment.TYPE_NECK) armors = CharacterItem.objects.filter(character = current_character, item__equipment__type = Equipment.TYPE_ARMOR) return render_to_response('lok/character.html', {'character': current_character, 'skills': skills, 'fame': fame, 'items': items, 'plots': plot_descriptions, 'achievements': achievements, 'title': title, 'swords': swords, 'bashing': bashing, 'bows': bows, 'feet': feet, 'cloaks': cloaks, 'clothes': clothes, 'gloves': gloves, 'rings': rings, 'neck': neck, 'armors': armors, 'esteems': esteems, 'titles': titles})
def update_with_result(self, result, pre_reqs, battle, block_death): changes = list() if self.actions == Character.MAX_ACTIONS: self.refill_time = datetime.utcnow().replace(tzinfo=utc) + timedelta(0, self.recharge_delay_secs) self.actions = self.actions - 1 if battle: # Increment the appropriate weapon skills. Always get 2pts in current weapon if it's a challenge, 1pt if it's easy (or someone else is fighting for us) odds = self.party.odds_against(battle) if odds["odds"] > 1 or odds["character"] != self: amount = 1 else: amount = 2 if odds["weapon"] == self.sword: stat = Stat.objects.get(name="Swordfighting") elif odds["weapon"] == self.bow: stat = Stat.objects.get(name="Archery") else: stat = Stat.objects.get(name="Bashing") if not CharacterStat.objects.filter(character=self, stat=stat): charstat = CharacterStat(character=self, stat=stat, value=0) else: charstat = CharacterStat.objects.get(character=self, stat=stat) change = Change(type=Change.TYPE_INCREMENT) change.name = stat.name change.old = charstat.value change.amount = amount charstat.value += amount change.new = charstat.value charstat.save() changes.append(change) stat_outcomes = StatOutcome.objects.filter(choice=result.pk) for outcome in stat_outcomes: stat, created = CharacterStat.objects.get_or_create(character=self, stat=outcome.stat) if level_from_value(stat.value) < outcome.maximum: change = Change(type=Change.TYPE_INCREMENT) change.old = stat.value oldlevel = level_from_value(stat.value) oldvalue = stat.value change.name = stat.stat.name # If we succeeded using a maxed stat, it can only increase by 1 point. if pre_reqs.filter(stat=outcome.stat) and pre_reqs.get(stat=outcome.stat).maximum <= oldlevel: stat.value += 1 else: stat.value += outcome.amount if stat.value < 0: stat.value = 0 change.amount = stat.value - oldvalue newlevel = level_from_value(stat.value) stat.save() if oldlevel != newlevel: change.type = Change.TYPE_LEVEL change.old = oldlevel change.new = newlevel change.amount = newlevel - oldlevel # ... and give them a free health point if they can use it. Note that we [currently] don't refill all health. if self.current_health < self.max_health(): self.current_health += 1 self.save() else: change.old = value_from_level(oldlevel + 1) - stat.value change.new = oldlevel + 1 changes.append(change) money_outcomes = MoneyOutcome.objects.filter(choice=result.pk) for outcome in money_outcomes: share = outcome.amount if battle and self.party.size() > 1: # Divide money among the team. share = (int)((outcome.amount * 1.25) / self.party.size()) for player in self.party.members(): if player != self: player.money += share player.save() notice = SocialMessage( to_character=player, description="You received " + str(share) + " royals from " + self.title_name() + "'s battle with " + battle.title + ".", ) notice.save() change = Change(type=Change.TYPE_MONEY) change.old = self.money self.money += share if outcome.amount == 1: change.name = "royal" else: change.name = "royals" # If we hit this test, we probably accidentally made the result amount bigger than the choice amount. if self.money < 0: self.money = 0 change.new = self.money change.amount = change.new - change.old changes.append(change) item_outcomes = ItemOutcome.objects.filter(result=result.pk) for outcome in item_outcomes: change = Change(type=Change.TYPE_ITEM) change.name = outcome.item.name item, created = CharacterItem.objects.get_or_create(character=self, item=outcome.item) change.old = item.quantity item.quantity += outcome.amount if item.quantity < 0: item.quantity = 0 change.new = item.quantity change.amount = change.new - change.old item.save() changes.append(change) health_outcomes = HealthOutcome.objects.filter(result=result.pk) for outcome in health_outcomes: change = Change(type=Change.TYPE_HEALTH) change.name = "health" change.old = self.current_health # If this was a fight, we have two chances to mitigate damage done. First dodge, then absorb. if battle: dodge_chance = self.stat_bonus(Stat.objects.get(name="Dodging")) if CharacterStat.objects.filter(character=self, stat__name="Dodging"): dodge_chance += level_from_value( CharacterStat.objects.get(character=self, stat__name="Dodging").value ) # Hard cap at 80% dodge rate. Should probably eventually turn this to a soft cap that kicks in much earlier. We also check on stat increase, but need to keep a check here as well to prevent someone reaching 100% through use of equipment. if dodge_chance > 80: dodge_chance = 80 if random.random() * 100 < dodge_chance: # They dodged it! No damage done. Let them know how lucky they are. changes.append(Change(type=Change.TYPE_DODGE)) outcome.amount = 0 # Next, let them absorb the blow if they have armor. armor_rating = self.stat_bonus(Stat.objects.get(name="Armor")) if armor_rating > 40: armor_rating = 40 old_outcome = outcome.amount outcome.amount = int(outcome.amount * (1.0 - float(armor_rating) * 2)) if old_outcome != outcome.amount: changes.append(Change(type=Change.TYPE_ABSORBED, amount=old_outcome - outcome.amount)) # See if they lucked out and gained an increase in dodge rating. if dodge_chance < self.level(): # Definitely play around with this! Right now I'm thinking the odds of a dodge increase will range between 1-5%, depending on the ratio between the character's stealth, deviousness and their level. max_dodgy = 0 if CharacterStat.objects.filter(character=self, stat__name="Deviousness"): max_dodgy = level_from_value( CharacterStat.objects.get(character=self, stat__name="Deviousness").value ) if CharacterStat.objects.filter(character=self, stat__name="Stealth"): stealthy = level_from_value( CharacterStat.objects.get(character=self, stat__name="Stealth").value ) if stealthy > max_dodgy: max_dodgy = stealthy odds = 0.01 + (0.04 * (max_dodgy / self.level())) if random.random() < odds: # Congrats! You just got better at dodging! dodgechange = Change(type=Change.TYPE_INCREMENT) dodgechange.name = "Dodging" if not CharacterStat.objects.filter(character=self, stat__name="Dodging"): dodgechange.old = 0 stat = CharacterStat(character=self, stat=Stat.objects.get(name="Dodging"), value=10) stat.save() else: stat = CharacterStat.objects.get(character=self, stat__name="Dodging") dodgechange.old = stat.value stat.value += 10 stat.save() dodgechange.amount = 10 dodgechange.new = stat.value changes.append(dodgechange) self.current_health += outcome.amount if self.current_health < 1 and block_death: self.current_health = 1 elif self.current_health < 0: self.current_health = 0 elif self.current_health > self.max_health(): self.current_health = self.max_health() if self.current_health != change.old: change.new = self.current_health change.amount = change.new - change.old changes.append(change) plot_outcomes = PlotOutcome.objects.filter(result=result.pk) for outcome in plot_outcomes: change = Change(type=Change.TYPE_PLOT) change.name = outcome.plot.description plot, created = CharacterPlot.objects.get_or_create(character=self, plot=outcome.plot) change.new = outcome.value plot.value = outcome.value plot.save() if plot.plot.achievement: changes.append(change) location_learn_outcomes = LearnLocationOutcome.objects.filter(choice=result.pk) for outcome in location_learn_outcomes: change = Change(type=Change.TYPE_LOCATION_LEARNED) change.name = outcome.location.name location, created = CharacterLocationAvailable.objects.get_or_create( character=self, location=outcome.location ) location.save() changes.append(change) title_outcomes = TitleOutcome.objects.filter(result=result.pk) for title_outcome in title_outcomes: change = Change(type=Change.TYPE_TITLE) change.name = macro(title_outcome.title.title(self), self) title, created = CharacterTitle.objects.get_or_create(character=self, title=title_outcome.title) title.save() changes.append(change) if SetLocationOutcome.objects.filter(choice=result.pk): outcome = SetLocationOutcome.objects.get(choice=result.pk) change = Change(type=Change.TYPE_LOCATION_CHANGED) change.name = outcome.location.name self.location = outcome.location changes.append(change) self.total_choices = self.total_choices + 1 self.save() return changes
def level(self): best_stat = CharacterStat.objects.filter(character=self, stat__type=Stat.TYPE_SKILL).order_by("-value")[0] return level_from_value(best_stat.value)
def level(self): return level_from_value(self.value)