def create_character_char_creator(cls, **kwargs): """Создание персонажа с использованием редактора""" world = get_active_world() race = kwargs['race'] pops = Pop.objects.select_related('location').filter( location__world_id=world.id, race=race) cell = choice(pops).location player = kwargs['player'] char = create_character_outta_nowhere(cell, 16, None, kwargs['gender']) control_tag = CharTag(character=char, name=CHAR_TAG_NAMES.CONTROLLED, content=f'{player.id}') control_tag.save() blood_tag = CharTag(character=char, name=CHAR_TAG_NAMES.BLOODLINE, content=f'{player.id}') blood_tag.save() spec = Trait.objects.get(name=f'exp.{kwargs["exp"]}1') spec.character.add(char) if kwargs["name"]: rr = RenameRequest(player=player, character=char, new_name=kwargs["name"]) rr.save() return char
def get_cell_projects(cls, char, x, y): if char is None: return [] if not char.is_alive: return [] try: cell = get_active_world()[x][y] loc = char.location dist = max(abs(loc['x'] - cell.x), abs(loc['y'] - cell.y)) char_can = get_available_projects(char) result = [] if RelocateHelpers.can_relocate(char, cell): result.append(PROJECTS.TYPES.RELOCATE) if dist <= BALANCE.BASE_COMMUNICATION_RANGE: population = cell.pop_set.count() if population == 0 and cell.main_biome != MAIN_BIOME.WATER: result += [ PROJECTS.TYPES.FORTIFY_CITY, PROJECTS.TYPES.BUILD_TILE ] elif population > 0: result += [ PROJECTS.TYPES.MAKE_FACTION, PROJECTS.TYPES.RENAME_TILE, PROJECTS.TYPES.IMPROVE_MANA, PROJECTS.TYPES.IMPROVE_FOOD, PROJECTS.TYPES.GATHER_SUPPORT ] return list(set(result) & set(char_can)) except Cell.DoesNotExist: return []
def roll_for_death(): world_age = get_active_world().ticks_age old_chars = Character.objects.filter(birth_date__lt=world_age - HEALTH.OLD_AGE) old_chars = old_chars.exclude( tags__name=CHAR_TAG_NAMES.DEATH) # No need to kill already dead for old_timer in old_chars: if randint(HEALTH.OLD_AGE, HEALTH.HARD_AGE_CAP) < old_timer.age: old_timer.die()
def process_pregancies(): world_age = get_active_world().ticks_age mothers = Character.objects.filter(tags__name=CHAR_TAG_NAMES.PREGNANCY) for mother in mothers: p = mother.pregnancy father = Character.objects.get(id=p['father']) if p['date'] <= world_age - CHILDREN.PREGNANCY_TICKS: if randint(1, 100) <= calc_stillborn_chance(mother): mother.pregnancy = None elif randint(1, 100) <= CHILDREN.TWINS_CHANCE: character_birth(mother, father) character_birth(mother, father) else: character_birth(mother, father)
def get_available_chars(cls, player): current = cls.get_current_char(player) world_age = get_active_world().ticks_age young_blood = Character.objects.filter( tags__name=CHAR_TAG_NAMES.BLOODLINE, tags__content=f'{player.id}' ).exclude(tags__name=CHAR_TAG_NAMES.CONTROLLED).exclude( primary_race=POP_RACE.FEY ).exclude( birth_date__gt=world_age - EXP. UNDERSTANDING_START #отсекаем персонажей до 4, т.к. у них нет проектов ) if current is not None: young_blood = young_blood.filter(birth_date__gt=current.birth_date) return young_blood
def target(self): kwargs = json.loads(self.arguments) target = kwargs.get('target', None) if target is None: return None if self.type in PROJECTS.TARGETS_CELL: return get_active_world()[int(target['x'])][int(target['y'])] if self.type in PROJECTS.TARGETS_CHARACTER: try: target = int(target) target = Character.objects.get(pk=target) return target except ValueError: return None except Character.DoesNotExist: return None
def calc_exp(char, subject, teacher_id = None , on_purpose = False): lvl = char.level(subject) # Дабы не лезть в БД лишние разы teacher_buff = 0 teacher_lvl_diff = 0 if teacher_id is not None: try: teacher = Character.objects.get(pk=int(teacher_id)) if teacher.current_project is not None: if teacher.current_project.name == p.TYPES.TEACH: #учитель должен учить kwargs = teacher.current_project.arguments_dict pupils = [] if len(kwargs['pupils'])>0: pupils = [int(i) for i in kwargs['pupils'].split(',')] if char.id in pupils and subject == kwargs['subject']: teacher_lvl_diff = max( teacher.level(subject) - lvl, 0) except Character.DoesNotExist: pass teacher_buff = EXP.TEACHER_LVL_BUFF * (teacher_lvl_diff -1) bloodline_buff = 0 bloodline_level = char.bloodline_level(subject) if bloodline_level > 0: bloodline_buff += EXP.BLOODLINE_PERK_BUFF if bloodline_level > lvl and char.controller is not None: bloodline_buff += EXP.BLOODLINE_MEMORY_BUFF age_buff = 0 world_age = get_active_world().ticks_age age = world_age - char.birth_date if age < EXP.UNDERSTANDING_START: return 0 elif age < EXP.EDUCATION_START: age_buff = EXP.TOO_YOUNG_EXP_MOD elif age < EXP.YOUNG_BUFF_CUTOFF: age_buff = EXP.YOUNG_EXP_MOD elif age>=EXP.OLD_DEBUFF_START: age_buff = EXP.TOO_OLD_EXP_MOD total_exp = EXP.NORMAL_EXP_GAIN + teacher_buff + bloodline_buff + age_buff if not on_purpose: total_exp = int(total_exp / 2) return max(total_exp, EXP.MINIMUM_EXP_GAINED)
def character_birth(mother, father): world_age = get_active_world().ticks_age gender = choice([GENDER.MALE, GENDER.FEMALE]) # Start name picking first_name_mother, last_name_mother = mother.name.split(None, maxsplit=1) first_name_father, last_name_father = father.name.split(None, maxsplit=1) #default to random first name first_name = hungarian.get_name_simple(gender).split()[0] #get grandparents of appropriate gender grandparents = mother.parents.filter( gender=gender) | father.parents.filter(gender=gender) grandparents = grandparents.distinct() if randint(1, 100) <= 25 and grandparents.count( ) > 0: # 25% chance to pick grandparent's first name first_name = choice([p.name.split()[0] for p in grandparents]) elif randint(1, 100) <= 10: # another roll, 10% to pick parent's first name first_name = first_name_father if gender == GENDER.MALE else first_name_mother mother_bc = mother.bloodlines.count() father_bc = father.bloodlines.count() weights = [mother_bc, father_bc] if mother_bc == 0 and father_bc == 0: weights = None last_name = choices([last_name_mother, last_name_father], weights=weights)[0] final_name = f'{first_name} {last_name}' child = Character(name=final_name, gender=gender, birth_date=world_age, primary_race=mother.primary_race, secondary_race=father.primary_race) child.save() child.location = mother.location child.add_parents(mother, father) add_racial_traits(child, mother, father) add_bloodlines(child, mother, father)
def handle(self, *args, **options): npcs = Character.objects.exclude(tags__name='controlled_by') #All Non-players npcs = npcs.exclude(traits__name__startswith='exp.') #who do not already have exp trait world_date = get_active_world().ticks_age templates = ['exp.science{lvl}','exp.economics{lvl}','exp.military{lvl}','exp.politics{lvl}'] for npc in npcs: age = world_date - npc.birth_date lvl = normal_npc_trait_gain(age) if options['verbosity']>2: print(npc.name,"age:",age,"lvl:",lvl) if lvl>0: tname = choice(templates).format(lvl=lvl) trait = Trait.objects.get(name=tname) if options['verbosity']>2: print("Added",trait.name,"to",npc.name) trait.character.add(npc)
def roll_for_pregnancies(): world_age = get_active_world().ticks_age min_age = world_age - CHILDREN.MIN_AGE males = Character.objects.filter(gender=GENDER.MALE).exclude( birth_date__gt=min_age) for m in males: weights = [] fs = list(get_available_females(m)) for f in fs: if f.is_enemy_of(m): weights.append(CHILDREN.ENEMY_ROLL_WEIGHT) elif f.is_friend_of(m): weights.append(CHILDREN.FRIEND_ROLL_WEIGHT) elif f.is_lover_of(m): weights.append(CHILDREN.LOVER_ROLL_WEIGHT) elif f.is_spouse_of(m): weights.append(CHILDREN.SPOUSE_ROLL_WEIGHT) else: weights.append(CHILDREN.NORMAL_ROLL_WEIGHT) rollnum = randint(0, CHILDREN.MAX_ROLLS_PER_MALE) partners = choices(fs, weights=weights, k=rollnum) for f in partners: roll = randint(1, 100) pregnancy = {'father': m.id, 'date': world_age} if f.is_enemy_of(m) and roll <= CHILDREN.ENEMY_PREGNANCY_CHANCE: f.pregnancy = pregnancy elif f.is_friend_of( m) and roll <= CHILDREN.FRIEND_PREGNANCY_CHANCE: f.pregnancy = pregnancy elif f.is_lover_of(m) and roll <= CHILDREN.LOVER_PREGNANCY_CHANCE: f.pregnancy = pregnancy elif f.is_spouse_of( m) and roll <= CHILDREN.SPOUSE_PREGNANCY_CHANCE: f.pregnancy = pregnancy elif roll <= CHILDREN.NORMAL_PREGNANCY_CHANCE: f.pregnancy = pregnancy
def start_cell_project(cls, char, x, y, project_type, data): allowed_projects = PCUtils.get_cell_projects(char, x, y) if project_type not in allowed_projects: raise cls.InvalidParameters( f"Your character ({char}) cannot start {project_type} project to target ({x}x{y})." ) cell = get_active_world()[x][y] proj_args = {'target': {'x': x, 'y': y}} if project_type == PROJECTS.TYPES.RELOCATE: if not RelocateHelpers.can_relocate_to_coords(char, x, y): raise cls.InvalidParameters( f"Your character ({char}) cannot relocate to target ({x}x{y})." ) project, created = char.projects.get_or_create( #get_or_create чтобы обновлять существующий проект, вместо пложения нового type = PROJECTS.TYPES.RELOCATE, defaults = { 'work_done':0, 'work_required':-1, 'is_current':False, 'arguments':json.dumps(proj_args) } ) project.is_current = True project.save() return project.id elif project_type == PROJECTS.TYPES.FORTIFY_CITY: missing = [] pop_str = data.get('with_pop', None) if pop_str is None: missing.append('with_pop') if len(missing) > 0: raise cls.MissingData( f"Request is missng POST parameters: {missing}.") pop_id = int(pop_str) player_cell = get_active_world()[char.location['x']][ char.location['y']] if not player_cell.pop_set.filter(pk=pop_id).exists(): raise cls.InvalidParameters( f"Your character ({char}) must be on the same cell with selected pop." ) project = char.projects.create( type=PROJECTS.TYPES.FORTIFY_CITY, work_done=0, work_required=PROJECTS.WORK.BASE_NEED, is_current=False) proj_args['with_pop'] = pop_id proj_args['target'] = {'x': x, 'y': y} project.arguments_dict = proj_args project.is_current = True project.save() return project.id elif project_type == PROJECTS.TYPES.BUILD_TILE: missing = [] pop_str = data.get('with_pop', None) city_type = data.get('city_type', None) if pop_str is None: missing.append('with_pop') if city_type is None: missing.append('city_type') if len(missing) > 0: raise cls.MissingData( f"Request is missng POST parameters: {missing}.") if city_type not in CIVILIAN_CITIES: raise cls.InvalidParameters( f"City type '{city_type}' cannot be built with this type of project" ) pop_id = int(pop_str) player_cell = get_active_world()[char.location['x']][ char.location['y']] if not player_cell.pop_set.filter(pk=pop_id).exists(): raise cls.InvalidParameters( f"Your character ({char}) must be on the same cell with selected pop." ) project = char.projects.create( type=PROJECTS.TYPES.BUILD_TILE, work_done=0, work_required=PROJECTS.WORK.BASE_NEED, is_current=False) proj_args['with_pop'] = pop_id proj_args['target'] = {'x': x, 'y': y} project.arguments_dict = proj_args project.is_current = True project.save() return project.id elif project_type == PROJECTS.TYPES.MAKE_FACTION: missing = [] pop_str = data.get('with_pop', None) name = data.get('name', None) if name is None: missing.append('name') if pop_str is None: missing.append('with_pop') if len(missing) > 0: raise cls.MissingData( f"Request is missng POST parameters: {missing}.") pop_id = int(pop_str) project = char.projects.create( type=PROJECTS.TYPES.MAKE_FACTION, work_done=0, work_required=PROJECTS.WORK.BASE_NEED, is_current=False) proj_args['with_pop'] = pop_id proj_args['author'] = char.controller.id proj_args['name'] = name project.arguments_dict = proj_args project.is_current = True project.save() return project.id elif project_type == PROJECTS.TYPES.RENAME_TILE: missing = [] name = data.get('name', None) if name is None: missing.append('name') if len(missing) > 0: raise cls.MissingData( f"Request is missng POST parameters: {missing}.") project = char.projects.create( type=PROJECTS.TYPES.RENAME_TILE, work_done=0, work_required=PROJECTS.WORK.BASE_NEED, is_current=False) proj_args['name'] = name proj_args['author'] = char.controller.id project.arguments_dict = proj_args project.is_current = True project.save() return project.id elif project_type == PROJECTS.TYPES.IMPROVE_MANA: project = char.projects.create( type=PROJECTS.TYPES.IMPROVE_MANA, work_done=0, work_required=PROJECTS.WORK.BASE_NEED, is_current=False) project.is_current = True project.save() return project.id elif project_type == PROJECTS.TYPES.IMPROVE_FOOD: project = char.projects.create( type=PROJECTS.TYPES.IMPROVE_FOOD, work_done=0, work_required=PROJECTS.WORK.BASE_NEED, is_current=False) project.is_current = True project.save() return project.id elif project_type == PROJECTS.TYPES.GATHER_SUPPORT: missing = [] pop_str = data.get('with_pop', None) if pop_str is None: missing.append('with_pop') if len(missing) > 0: raise cls.MissingData( f"Request is missng POST parameters: {missing}.") pop_id = int(pop_str) if not cell.pop_set.filter(pk=pop_id).exists(): raise cls.InvalidParameters( f"Selected pop must be on specified cell.") project = char.projects.create( type=PROJECTS.TYPES.GATHER_SUPPORT, work_done=0, work_required=PROJECTS.WORK.BASE_NEED, is_current=False) proj_args['with_pop'] = pop_id project.arguments_dict = proj_args project.is_current = True project.save() return project.id
def die(self): world_age = get_active_world().ticks_age t = CharTag(character=self, name=CHAR_TAG_NAMES.DEATH, content=f'{world_age}') t.save()
def age(self): world_age = get_active_world().ticks_age return world_age - self.birth_date
def can_relocate_to_coords(cls, char , x, y): try: target = get_active_world().cell_set.get(x = x, y= y) return cls.can_relocate(char, target) except Cell.DoesNotExist: return False