from django.db import models from django.contrib.auth.models import User # Create your models here. class GameSystem(models.Model): name = models.CharField(max_length=255, unique=True) description = models.TextField(null=True) def __str__(self): return self.name class GM(models.Model): gm = models.ForeignKey(User, on_delete=models.CASCADE) campaign = models.ForeignKey("Campaign", null=True, on_delete=models.CASCADE, related_name='campaign') class Player(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) status = models.CharField(max_length=255, unique=True) # # class Players(models.Model): # player = models.ForeignKey(User, on_delete=models.CASCADE) # status = models.CharField(max_length=255, unique=True) class Campaign(models.Model): name = models.CharField(max_length=255, unique=True) description = models.TextField(null=True) game_system = models.ForeignKey(GameSystem, on_delete=models.CASCADE) gm = models.ManyToManyField('GM', related_name='GM') player = models.ManyToManyField('Player') def __str__(self): return self.name class GURPSCharacter(models.Model): uuid = models.CharField(max_length=128, unique=True) name = models.CharField(max_length=255, unique=True) player = models.ForeignKey(Player, null=True, on_delete=models.CASCADE) campaign = models.ForeignKey(Campaign, null=True, on_delete=models.CASCADE) details = models.JSONField() # owner => user # campaign => campaign def __str__(self): return self.name + " Player " + str(self.player) + " Campaign " + str(self.campaign) def adv_points(self): return sum([a['calc']['points'] for a in self.details.get('advantages', []) if a['calc']['points'] > 0]) def disadv_points(self): return sum([a['calc']['points'] for a in self.details.get('advantages', []) if a['calc']['points'] < -1]) def quirks_points(self): return sum([a['calc']['points'] for a in self.details.get('advantages', []) if a['calc']['points'] == -1]) def attr_points(self): return sum([a['calc']['points'] for a in self.details['attributes']]) def skills_points(self): return sum([s['points'] for s in self.details.get('skills', [])]) def spells_points(self): return sum([s['points'] for s in self.details.get('spells', [])]) def race_points(self): return sum([s['points'] for s in self.details.get('race', [])]) # Are we sure? def unspent_points(self): return self.details['total_points'] - self.adv_points() - \ self.disadv_points() - self.attr_points() - \ self.skills_points() - self.spells_points() - \ self.race_points() - self.quirks_points() def get_primary_attr(self, attr_id): return [a['calc'] for a in self.details['attributes'] if a['attr_id'] == attr_id][0] def st(self): return self.get_primary_attr('st') def iq(self): return self.get_primary_attr('iq') def dx(self): return self.get_primary_attr('dx') def ht(self): return self.get_primary_attr('ht') def will(self): return self.get_primary_attr('will') def fright_check(self): return self.get_primary_attr('fright_check') def per(self): return self.get_primary_attr('per') def vision(self): return self.get_primary_attr('vision') def hearing(self): return self.get_primary_attr('hearing') def taste_smell(self): return self.get_primary_attr('taste_smell') def touch(self): return self.get_primary_attr('touch') def basic_move(self): return self.get_primary_attr('basic_move') def basic_speed(self): return self.get_primary_attr('basic_speed') def hp(self): return self.get_primary_attr('hp') def fp(self): return self.get_primary_attr('fp') def weight_carried(self): items = [i['calc']['extended_weight'] for i in self.details['equipment']] total_weight = 0 for i in items: total_weight += float(i.split()[0]) return total_weight def enc_level(self): if self.weight_carried() <= self.basic_lift(): return 0 elif self.weight_carried() <= self.basic_lift() * 2: return 1 elif self.weight_carried() <= self.basic_lift() * 3: return 2 elif self.weight_carried() <= self.basic_lift() * 6: return 3 else: return 4 def enc_levels(self): enc_level = self.enc_level() dodge = self.details["calc"]["dodge"][0] basic_move = self.basic_move()["value"] return [ { "max_load": round(self.basic_lift()), "move": basic_move, "dodge": dodge, "current": "current" * (enc_level == 0) }, { "max_load": round(self.basic_lift()) * 2, "move": basic_move - 2, "dodge": dodge - 1, "current": "current" * (enc_level == 1) }, { "max_load": round(self.basic_lift()) * 3, "move": basic_move - 3, "dodge": dodge - 2, "current": "current" * (enc_level == 2) }, { "max_load": round(self.basic_lift()) * 6, "move": basic_move - 4, "dodge": dodge - 3, "current": "current" * (enc_level == 3) }, { "max_load": round(self.basic_lift()) * 10, "move": basic_move - 5, "dodge": dodge - 4, "current": "current" * (enc_level == 4) }, ] def basic_lift(self): return float(self.details["calc"]["basic_lift"].split()[0]) def weight_unit(self): return self.details['settings']['default_weight_units'] def lift_table(self): return [ {"value": round(self.basic_lift()), "label": "Basic Lift"}, {"value": round(self.basic_lift()) * 2, "label": "One-Handed Lift"}, {"value": round(self.basic_lift()) * 8, "label": "Two-Handed Lift"}, {"value": round(self.basic_lift()) * 12, "label": "Shove &ersand; Knock Over"}, {"value": round(self.basic_lift()) * 24, "label": "Running Shove & Knock Over"}, {"value": round(self.basic_lift()) * 15, "label": "Carry on Back"}, {"value": round(self.basic_lift()) * 50, "label": "Shift Slightly"}, ] def reaction_modifiers(self): modifiers = [] for a in self.details.get('advantages', []): if "features" in a: for f in a["features"]: if f["type"] == "reaction_bonus": modifiers.append(f) return modifiers def conditional_modifiers(self): modifiers = [] for a in self.details.get('advantages', []): if "features" in a: for f in a["features"]: if f["type"] == "conditional_modifier": modifiers.append(f) return modifiers def weapons(self): return [w for w in self.details['equipment'] if "weapons" in w] + \ [a for a in self.details.get("advantages", []) if "weapons" in a] + \ [a for a in self.details.get("traits", []) if "weapons" in a] + \ [s for s in self.details.get("spells", []) if "weapons" in s] def melee_weapons(self): mw = [] for item in self.weapons(): for weapon in item["weapons"]: if weapon["type"] == "melee_weapon": if "description" in item: name = item["description"] else: name = item["name"] mw.append( { "name": name, "usage": weapon["usage"], "skill_level": weapon["calc"].get("level", 0), "parry": weapon["calc"].get("parry", "No"), "block": weapon["calc"].get("block", "No"), "damage": weapon["calc"]["damage"], "reach": weapon["calc"].get("reach", ""), "strength": weapon.get("strength", " ") } ) return mw def ranged_weapons(self): def muscle_range(wpn_range): if wpn_range.startswith("x"): ranges = wpn_range.split("/") new_ranges = [] for wpn_range in ranges: wpn_range = float(wpn_range[1:]) wpn_range = wpn_range * self.st()["value"] wpn_range = str(wpn_range) wpn_range = wpn_range[:wpn_range.index(".")] new_ranges.append(wpn_range) return "/".join(new_ranges) else: return wpn_range rw = [] for item in self.weapons(): for weapon in item["weapons"]: if weapon["type"] == "ranged_weapon": if "description" in item: name = item["description"] else: name = item["name"] rw.append( { "name": name, "bulk": weapon.get("bulk", " "), "usage": weapon.get("usage", " "), "skill_level": weapon["calc"]["level"], "damage": weapon["calc"]["damage"], "strength": weapon.get("strength", " "), "acc": weapon.get("accuracy", 0), "range": muscle_range(weapon.get("range", " ")), "rof": weapon.get("rate_of_fire", " "), "shots": weapon.get("shots", " "), "recoil": weapon.get("recoil", " ") } ) return rw def traits(self): traits = [] for advantage in self.details.get("advantages", []): cost = advantage["calc"]["points"] name = advantage["name"] if "categories" in advantage and "Language" in advantage["categories"]: levels = [m for m in advantage['modifiers'] if "disabled" not in m] notes = "" for level in levels: notes += f"{level['name']}" if "notes" in level: notes += f" ({level['notes']}); " else: notes += "; " notes = notes[:-2] elif "notes" in advantage: notes = advantage["notes"] elif "modifiers" in advantage: notes = [m for m in advantage['modifiers'] if m["cost"] == cost][0]["name"] else: notes = "" traits.append({"name": name, "notes": notes, "points": cost, "reference": advantage["reference"]}) return traits def spells(self): def get_casting_details(spell_details): level = spell_details['calc']['level'] if level < 10: descr = ( "Ritual: Need both hands and both feet " "free, and must speak .Time: 2x." ) elif level < 15: descr = ( "Ritual: Must speak a few quiet words " "and make a gesture." ) elif level < 20: descr = ( "Ritual: Must speak a word or two or make " "a small gesture. May move one yard per second " "while concentrating. Cost: -1." ) elif level < 25: descr = "Ritual: None. Time: / 2 (round up). Cost: -2." elif level < 30: descr = ( "Ritual: None. Time: / 4 (round up). Cost: -3." ) else: delta = int((level - 25) / 5) power = 2 + delta # divisor = 2**power cost = 3 + delta descr = ( f"Ritual: None. Time: / {power} round up. Cost: " f"-{cost}" ) return descr spells = [] for spell in self.details.get('spells', []): notes = ( f"{get_casting_details(spell)}
Class: {spell['spell_class']}; " f"Cost: {spell['casting_cost']}; Maintain: {spell['maintenance_cost']};" f" Time: {spell['casting_time']}; Duration: {spell['duration']}; " ) spells.append( { 'name': spell["name"], "college": ", ".join(spell["college"]), "level": spell["calc"]["level"], "rsl": spell["calc"]["rsl"], "points": spell["points"], "reference": spell["reference"], "notes": notes } ) return spells def skills(self): skills = [] for skill in self.details.get('skills', []): skills.append({ 'name': skill["name"], "level": skill["calc"]["level"], "rsl": skill["calc"]["rsl"], "points": skill["points"], "reference": skill["reference"] }) return skills def equipment(self): def get_children(parent, level=1): children = [] for item_details in parent["children"]: equipment_details = { "name": item_details["description"], "uses": "", "tech_level": item_details["tech_level"], "lc": "", "value": item_details["value"], "weight": item_details["weight"], "quantity": item_details.get("quantity", 1), "ref": item_details["reference"], "ext_weight": item_details["calc"]["extended_weight"], "ext_value": item_details["calc"]["extended_value"], "notes": item_details.get("notes", ""), "equipped": item_details["equipped"], "level": level } children.append(equipment_details) if "children" in item_details: children += get_children(item_details, level + 1) return children equipment = self.details['equipment'] equipment_list = [] for item in equipment: equipment_list.append( { "name": item["description"], "uses": "", "tech_level": item["tech_level"], "lc": "", "level": 0, "value": item["value"], "weight": item["weight"], "quantity": item.get("quantity", 1), "ref": item.get("reference", ""), "ext_weight": item["calc"]["extended_weight"], "ext_value": item["calc"]["extended_value"], "notes": item.get("notes", ""), "equipped": item["equipped"] } ) if 'children' in item: equipment_list += get_children(item) return equipment_list def hit_locations(self): try: # v2 return self.details["settings"]["hit_locations"]["locations"] except KeyError: # v4 return self.details["settings"]["body_type"]["locations"]