예제 #1
0
파일: build.py 프로젝트: coolkat64/rolling
    def perform(
        self, character: "CharacterModel", build_id: int, input_: typing.Any
    ) -> Description:
        build_doc = self._kernel.build_lib.get_build_doc(build_id)

        if input_.quantity is None:
            build_description = self._kernel.game.config.builds[build_doc.build_id]
            required_resource = next(
                (
                    brr
                    for brr in build_description.build_require_resources
                    if brr.resource_id == input_.resource_id
                )
            )
            resource_description, left, left_percent = self.get_resource_infos(
                self._kernel, required_resource, build_doc=build_doc
            )
            left_str = quantity_to_str(left, resource_description.unit, kernel=self._kernel)
            unit_str = self._kernel.translation.get(resource_description.unit)

            return Description(
                title=f"Cette construction nécessite encore {left_str} "
                f"de {resource_description.name} (soit {round(left_percent)}%)",
                can_be_back_url=True,
                items=[
                    Part(
                        is_form=True,
                        form_values_in_query=True,
                        form_action=get_with_build_action_url(
                            character_id=character.id,
                            build_id=build_id,
                            action_type=ActionType.BRING_RESOURCE_ON_BUILD,
                            action_description_id=self._description.id,
                            query_params=self.input_model_serializer.dump(input_),
                        ),
                        items=[
                            Part(
                                label=f"Quantité ({unit_str}) ?", type_=Type.NUMBER, name="quantity"
                            )
                        ],
                    )
                ],
            )

        resource_description = self._kernel.game.config.resources[input_.resource_id]
        try:
            self._kernel.resource_lib.reduce_carried_by(
                character.id, resource_id=input_.resource_id, quantity=input_.quantity, commit=False
            )
        except (NotEnoughResource, NoCarriedResource):
            raise ImpossibleAction(
                f"{character.name} ne possède pas assez de {resource_description.name}"
            )

        self._kernel.resource_lib.add_resource_to(
            build_id=build_doc.id,
            resource_id=input_.resource_id,
            quantity=input_.quantity,
            commit=False,
        )
        self._kernel.server_db_session.commit()

        build_description = self._kernel.game.config.builds[build_doc.build_id]
        quantity_str = quantity_to_str(
            input_.quantity, resource_description.unit, kernel=self._kernel
        )

        return Description(
            title=f"{quantity_str} {resource_description.name} déposé pour {build_description.name}",
            items=[
                Part(is_link=True, go_back_zone=True, label="Retourner à l'écran de déplacements"),
                Part(
                    label="Voir le batiment",
                    is_link=True,
                    form_action=DESCRIBE_BUILD.format(
                        build_id=build_doc.id, character_id=character.id
                    ),
                ),
            ],
            force_back_url=f"/_describe/character/{character.id}/build_actions",
        )
예제 #2
0
    async def manage_requests(self, request: Request,
                              hapic_data: HapicData) -> Description:
        # TODO BS: only chief (or ability) can display this
        affinity = self._kernel.affinity_lib.get_affinity(
            hapic_data.path.affinity_id)
        relation = self._kernel.affinity_lib.get_character_relation(
            affinity_id=hapic_data.path.affinity_id,
            character_id=hapic_data.path.character_id)
        requests: typing.List[
            AffinityRelationDocument] = self._kernel.server_db_session.query(
                AffinityRelationDocument).filter(
                    AffinityRelationDocument.affinity_id == affinity.id,
                    AffinityRelationDocument.accepted == False,
                    AffinityRelationDocument.request == True,
                ).all()

        data = {}
        try:
            data = await request.json()
        except JSONDecodeError:
            pass

        request: AffinityRelationDocument
        if data:
            for request in list(requests):
                choose = data.get(request.character_id)
                if choose:
                    if choose == "Accepter":
                        request.accepted = True
                        request.request = False
                        request.status_id = affinity.default_status_id
                    elif choose == "Refuser":
                        request.accepted = False
                        request.request = False
                        request.disallowed = True

                    self._kernel.server_db_session.add(request)
                    self._kernel.server_db_session.commit()
                    requests.remove(request)

        form_parts = []
        for request in requests:
            character = self._kernel.character_lib.get_document(
                request.character_id)
            form_parts.append(
                Part(
                    label=f"{character.name}",
                    name=character.id,
                    choices=["Ne rien décider", "Accepter", "Refuser"],
                    value="Ne rien décider",
                ))

        return Description(
            title=f"Demande(s) d'adhésion pour {affinity.name}",
            items=[
                Part(
                    is_form=True,
                    submit_label="Enregistrer",
                    form_action=(f"/affinity/{hapic_data.path.character_id}"
                                 f"/manage-requests/{affinity.id}"),
                    items=form_parts,
                )
            ],
            footer_links=[
                Part(is_link=True,
                     go_back_zone=True,
                     label="Retourner à l'écran de déplacements"),
                Part(
                    is_link=True,
                    label=f"Voir la fiche de {affinity.name}",
                    form_action=
                    f"/affinity/{hapic_data.path.character_id}/see/{affinity.id}",
                    classes=["primary"],
                ),
                Part(
                    is_link=True,
                    label="Voir les affinités",
                    form_action=f"/affinity/{hapic_data.path.character_id}",
                ),
            ],
            can_be_back_url=True,
        )
예제 #3
0
    async def manage_relation(self, request: Request,
                              hapic_data: HapicData) -> Description:
        # TODO BS: only chief (or ability) can display this
        affinity = self._kernel.affinity_lib.get_affinity(
            hapic_data.path.affinity_id)
        displayer_relation = self._kernel.affinity_lib.get_character_relation(
            affinity_id=hapic_data.path.affinity_id,
            character_id=hapic_data.path.character_id)
        relation = self._kernel.affinity_lib.get_character_relation(
            affinity_id=hapic_data.path.affinity_id,
            character_id=hapic_data.path.relation_character_id,
        )
        character_doc = self._kernel.character_lib.get_document(
            hapic_data.path.relation_character_id)
        # for now, only permit manage member
        assert relation.accepted
        here_url = (f"/affinity/{hapic_data.path.character_id}"
                    f"/manage-relations/{affinity.id}/{character_doc.id}")
        statuses = dict(json.loads(affinity.statuses))

        if hapic_data.query.disallowed is not None and hapic_data.query.disallowed:
            relation.disallowed = True
            relation.accepted = False
            self._kernel.server_db_session.add(relation)
            self._kernel.server_db_session.commit()
            return Description(
                redirect=f"/affinity/{hapic_data.path.character_id}")

        if hapic_data.body.status:
            status_id = list(statuses.keys())[list(statuses.values()).index(
                hapic_data.body.status)]
            relation.status_id = status_id
            self._kernel.server_db_session.add(relation)
            self._kernel.server_db_session.commit()

        status_str = statuses[relation.status_id]
        return Description(
            title=character_doc.name,
            items=[
                Part(
                    is_link=True,
                    form_action=here_url + "?disallowed=1",
                    label=f"Exclure {character_doc.name}",
                ),
                Part(
                    is_form=True,
                    form_action=here_url,
                    items=[
                        Part(
                            label=
                            f"Changer le status de {character_doc.name} ?",
                            choices=list(statuses.values()),
                            value=status_str,
                            name="status",
                        )
                    ],
                ),
            ],
            footer_links=[
                Part(is_link=True,
                     go_back_zone=True,
                     label="Retourner à l'écran de déplacements"),
                Part(
                    is_link=True,
                    label=f"Voir la fiche de {affinity.name}",
                    form_action=
                    f"/affinity/{hapic_data.path.character_id}/see/{affinity.id}",
                    classes=["primary"],
                ),
                Part(
                    is_link=True,
                    label="Voir les affinités",
                    form_action=f"/affinity/{hapic_data.path.character_id}",
                ),
            ],
            can_be_back_url=True,
        )
예제 #4
0
    async def main_page(self, request: Request,
                        hapic_data: HapicData) -> Description:
        affiliated_parts = []
        for relation, affinity in self._kernel.affinity_lib.get_with_relation(
                character_id=hapic_data.path.character_id):
            rel_str = ""
            if relation.accepted:
                rel_str = dict(json.loads(
                    affinity.statuses))[relation.status_id]
            elif relation.rejected:
                rel_str = "Quitté"
            elif relation.disallowed:
                rel_str = "Exclu"
            elif relation.request:
                rel_str = "Demandé"
            elif not relation.accepted and not relation.request and not relation.fighter:
                rel_str = "Plus de lien"
            if relation.fighter:
                if rel_str:
                    rel_str = f"{rel_str}, Combattant"
                else:
                    rel_str = "Combattant"
            rel_str = f"({rel_str})" if rel_str else ""
            label = f"{affinity.name} {rel_str}"

            if self._kernel.affinity_lib.there_is_unvote_relation(
                    affinity, relation):
                label = f"*{label}"

            affiliated_parts.append(
                Part(
                    is_link=True,
                    form_action=
                    f"/affinity/{hapic_data.path.character_id}/see/{affinity.id}",
                    label=label,
                ))

        return Description(
            title="Affinités",
            items=[
                Part(
                    text=
                    "Les affinités permettent d'exprimer à quelles communautés se rattache "
                    "votre personnage."),
                Part(
                    label="Créer une affinité",
                    is_link=True,
                    form_action=f"/affinity/{hapic_data.path.character_id}/new",
                ),
                Part(
                    label="Rejoindre une affinité",
                    is_link=True,
                    form_action=
                    f"/affinity/{hapic_data.path.character_id}/list",
                ),
                Part(
                    text=
                    "Ci-dessous les affinités avec lesquelles vous etes affiliés"
                ),
            ] + affiliated_parts,
            can_be_back_url=True,
        )
예제 #5
0
    async def manage(self, request: Request,
                     hapic_data: HapicData) -> Description:
        # TODO BS: only chief (or ability) can display this
        affinity = self._kernel.affinity_lib.get_affinity(
            hapic_data.path.affinity_id)
        relation = self._kernel.affinity_lib.get_character_relation(
            affinity_id=hapic_data.path.affinity_id,
            character_id=hapic_data.path.character_id)

        if hapic_data.query.join_type == affinity_join_str[
                AffinityJoinType.ACCEPT_ALL]:
            request_relations = (self._kernel.server_db_session.query(
                AffinityRelationDocument).filter(
                    AffinityRelationDocument.request == True,
                    AffinityRelationDocument.accepted == False,
                    AffinityRelationDocument.affinity_id == affinity.id,
                ).all())
            if len(request_relations) and not hapic_data.query.confirm:
                return Description(
                    title=affinity.name,
                    items=[
                        Part(
                            text=f'Choisir "{hapic_data.query.join_type}" '
                            f"acceptera automatiquement {len(request_relations)} demande(s) "
                            f"en attente"),
                        Part(
                            label="Confirmer",
                            is_link=True,
                            form_action=
                            f"/affinity/{hapic_data.path.character_id}"
                            f"/manage/{affinity.id}"
                            f"?join_type={urllib.parse.quote(hapic_data.query.join_type)}"
                            f"&confirm=1",
                        ),
                        Part(
                            label="Annuler",
                            is_link=True,
                            form_action=
                            f"/affinity/{hapic_data.path.character_id}"
                            f"/manage/{affinity.id}",
                        ),
                    ],
                )

        # proceed submited data
        if hapic_data.query.join_type is not None:
            join_type = list(affinity_join_str.keys())[list(
                affinity_join_str.values()).index(hapic_data.query.join_type)]

            # TODO BS: code it
            if join_type not in [
                    AffinityJoinType.ACCEPT_ALL,
                    AffinityJoinType.ONE_CHIEF_ACCEPT
            ]:
                raise RollingError(
                    "Cette fonctionnalite n'est pas encore disponible")

            if join_type == AffinityJoinType.ACCEPT_ALL:
                self._kernel.server_db_session.query(
                    AffinityRelationDocument).filter(
                        AffinityRelationDocument.request == True,
                        AffinityRelationDocument.accepted == False,
                        AffinityRelationDocument.affinity_id == affinity.id,
                    ).update({
                        "accepted": True,
                        "request": False
                    })

            affinity.join_type = join_type.value
            self._kernel.server_db_session.add(affinity)
            self._kernel.server_db_session.commit()
            return Description(
                redirect=
                f"/affinity/{hapic_data.path.character_id}/manage/{affinity.id}"
            )

        join_values = [
            affinity_join_str[AffinityJoinType.ACCEPT_ALL],
            affinity_join_str[AffinityJoinType.ONE_CHIEF_ACCEPT],
            affinity_join_str[AffinityJoinType.HALF_STATUS_ACCEPT],
        ]

        request_count = (self._kernel.server_db_session.query(
            AffinityRelationDocument).filter(
                AffinityRelationDocument.affinity_id == affinity.id,
                AffinityRelationDocument.accepted == False,
                AffinityRelationDocument.request == True,
            ).count())
        member_count = (self._kernel.server_db_session.query(
            AffinityRelationDocument).filter(
                AffinityRelationDocument.affinity_id == affinity.id,
                AffinityRelationDocument.accepted == True,
            ).count())
        parts = [
            Part(
                label=
                f"Il y a actuellement {request_count} demande(s) d'adhésion",
                is_link=bool(request_count),
                form_action=
                (f"/affinity/{hapic_data.path.character_id}/manage-requests/{affinity.id}"
                 ),
            ),
            Part(
                label=f"Il y a actuellement {member_count} membre(s)",
                is_link=True,
                form_action=
                (f"/affinity/{hapic_data.path.character_id}/manage-relations/{affinity.id}"
                 ),
            ),
        ]

        return Description(
            title=f"Administration de {affinity.name}",
            items=[
                Part(
                    is_form=True,
                    form_values_in_query=True,
                    submit_label="Enregistrer",
                    form_action=
                    f"/affinity/{hapic_data.path.character_id}/manage/{affinity.id}",
                    items=[
                        Part(
                            label="Mode d'admission des nouveaux membres",
                            choices=join_values,
                            name="join_type",
                            value=affinity_join_str[AffinityJoinType(
                                affinity.join_type)],
                        )
                    ],
                )
            ] + parts,
            footer_links=[
                Part(is_link=True,
                     go_back_zone=True,
                     label="Retourner à l'écran de déplacements"),
                Part(
                    is_link=True,
                    label="Voir les affinités",
                    form_action=f"/affinity/{hapic_data.path.character_id}",
                ),
            ],
            can_be_back_url=True,
        )
예제 #6
0
    async def see(self, request: Request,
                  hapic_data: HapicData) -> Description:
        affinity = self._kernel.affinity_lib.get_affinity(
            hapic_data.path.affinity_id)
        relation = self._kernel.affinity_lib.get_character_relation(
            affinity_id=hapic_data.path.affinity_id,
            character_id=hapic_data.path.character_id)
        character = self._kernel.character_lib.get(
            hapic_data.path.character_id)
        member_count = self._kernel.affinity_lib.count_members(
            hapic_data.path.affinity_id)
        fighter_count = self._kernel.affinity_lib.count_members(
            hapic_data.path.affinity_id, fighter=True)

        parts = []
        edit_relation_url = (
            f"/affinity/{hapic_data.path.character_id}/edit-relation/{hapic_data.path.affinity_id}"
        )
        if relation:
            fighter_str = ""
            if relation.fighter:
                fighter_str = " (Vous vous battez pour elle)"

            status_str = (dict(json.loads(
                affinity.statuses))[relation.status_id]
                          if relation.status_id else "")
            if relation.accepted:
                parts.append(
                    Part(
                        label=
                        (f"Vous êtes membre de cette affinité et vous portez le status "
                         f"de {status_str}{fighter_str}"),
                        is_link=True,
                        form_action=edit_relation_url,
                    ))
            elif relation.request:
                parts.append(
                    Part(
                        label=
                        f"Vous avez demandé à être membre de cette affinité{fighter_str}",
                        is_link=True,
                        form_action=edit_relation_url,
                    ))
            elif relation.rejected:
                parts.append(
                    Part(
                        label=f"Vous avez renié cette affinité{fighter_str}",
                        is_link=True,
                        form_action=edit_relation_url,
                    ))
            elif relation.disallowed:
                parts.append(
                    Part(
                        label=
                        f"Vous avez été rejeté de cette affinité{fighter_str}",
                        is_link=True,
                        form_action=edit_relation_url,
                    ))
            elif relation.fighter:
                parts.append(
                    Part(
                        label="Vous combattez pour cette affinité",
                        is_link=True,
                        form_action=edit_relation_url,
                    ))
            else:
                parts.append(
                    Part(
                        label=
                        "Vous n'avez plus aucune relation avec cette affinité",
                        is_link=True,
                        form_action=edit_relation_url,
                    ))
        else:
            parts.append(
                Part(
                    label="Vous n'avez aucune relation avec cette affinité",
                    is_link=True,
                    form_action=edit_relation_url,
                ))

        # can access management page ?
        if affinity.direction_type == AffinityDirectionType.ONE_DIRECTOR.value:
            if relation and relation.status_id == CHIEF_STATUS[0]:
                need_action = (
                    "*" if self._kernel.affinity_lib.there_is_unvote_relation(
                        affinity, relation) else "")
                parts.extend([
                    Part(
                        label=f"{need_action}Gérer cette affinité",
                        is_link=True,
                        form_action=
                        f"/affinity/{hapic_data.path.character_id}/manage/{affinity.id}",
                    )
                ])

        if (ActionType.FOLLOW_CHARACTER in self._kernel.game.config.actions
                and ActionType.STOP_FOLLOW_CHARACTER
                in self._kernel.game.config.actions):
            follow_action = self._kernel.action_factory.create_action(
                ActionType.FOLLOW_CHARACTER, ActionType.FOLLOW_CHARACTER.name)
            stop_follow_action = self._kernel.action_factory.create_action(
                ActionType.STOP_FOLLOW_CHARACTER,
                ActionType.STOP_FOLLOW_CHARACTER.name)
            for followable_character in self._kernel.affinity_lib.get_chief_or_warlord_of_affinity(
                    affinity.id,
                    row_i=character.world_row_i,
                    col_i=character.world_col_i):
                if followable_character.id == character.id:
                    break

                for action in [follow_action, stop_follow_action]:
                    try:
                        action.check_is_possible(character,
                                                 followable_character)
                        parts.extend([
                            Part(
                                text=action_link.get_as_str(),
                                form_action=action_link.link,
                                is_link=True,
                                link_group_name=action_link.group_name,
                            ) for action_link in action.get_character_actions(
                                character, followable_character)
                        ])
                    except ImpossibleAction:
                        pass

        return Description(
            title=affinity.name,
            items=[
                Part(text=affinity.description),
                Part(
                    text=
                    f"D'après les dires, cette affinité compte {member_count} membre(s) "
                    f"dont {fighter_count} prêt(s) à se battre. Pour plus de renseignements "
                    f"sur ces personnes dans la zone où se trouve votre personnage, "
                    f"rendez-vous sur la page de la zone."),
            ] + parts,
            footer_links=[
                Part(
                    is_link=True,
                    label="Retour aux affinités",
                    form_action=f"/affinity/{hapic_data.path.character_id}",
                )
            ],
            can_be_back_url=True,
        )
예제 #7
0
    async def edit_relation(self, request: Request,
                            hapic_data: HapicData) -> Description:
        affinity = self._kernel.affinity_lib.get_affinity(
            hapic_data.path.affinity_id)
        relation = self._kernel.affinity_lib.get_character_relation(
            affinity_id=hapic_data.path.affinity_id,
            character_id=hapic_data.path.character_id)

        if (hapic_data.query.request is not None
                or hapic_data.query.rejected is not None
                or hapic_data.query.fighter is not None):
            title = "ERROR"
            return_ = False
            if hapic_data.query.request and relation:
                title = f"Requete pour etre membre de {affinity.name} exprimé"
                if affinity.join_type == AffinityJoinType.ACCEPT_ALL and not (
                        relation.disallowed or relation.rejected):
                    relation.accepted = True
                else:
                    relation.request = True
                return_ = True
            elif hapic_data.query.request == 0 and relation:
                title = f"Vous ne demandez plus à être membre de {affinity.name}"
                relation.request = False
                return_ = True
            elif hapic_data.query.request and not relation:
                title = f"Requete pour etre membre de {affinity.name} exprimé"
                self._kernel.affinity_lib.join(
                    character_id=hapic_data.path.character_id,
                    affinity_id=hapic_data.path.affinity_id,
                    accepted=True if affinity.join_type
                    == AffinityJoinType.ACCEPT_ALL.value else False,
                    fighter=True if hapic_data.query.fighter else False,
                    request=True,
                )
                return_ = True
            elif hapic_data.query.rejected and not relation:
                pass  # should not be here
            elif hapic_data.query.rejected and relation:
                title = f"Vous avez déclaré avoir abandonné {affinity.name}"
                relation.accepted = False
                relation.request = False
                relation.rejected = True
                return_ = True
            elif hapic_data.query.fighter and not relation:
                title = f"Vous vous battez désormais pour {affinity.name}"
                self._kernel.affinity_lib.join(
                    character_id=hapic_data.path.character_id,
                    affinity_id=hapic_data.path.affinity_id,
                    accepted=True if affinity.join_type
                    == AffinityJoinType.ACCEPT_ALL else False,
                    fighter=True,
                    request=False,
                )
                return_ = True
            elif hapic_data.query.fighter and relation:
                title = (f"Vous combatrez désormais dès lors qu'un membre de"
                         f" {affinity.name} sera attaqué")
                relation.fighter = True
                return_ = True
            elif hapic_data.query.fighter == 0:
                title = (
                    f"Vous ne combatrez désormais plus lorsqu'un membre de"
                    f" {affinity.name} sera attaqué")
                relation.fighter = False
                return_ = True

            if return_:
                self._kernel.server_db_session.commit()
                return Description(
                    title=title,
                    footer_links=[
                        Part(
                            is_link=True,
                            go_back_zone=True,
                            label="Retourner à l'écran de déplacements",
                        ),
                        Part(
                            is_link=True,
                            label=f"Voir la fiche de {affinity.name}",
                            form_action=
                            f"/affinity/{hapic_data.path.character_id}/see/{affinity.id}",
                            classes=["primary"],
                        ),
                        Part(
                            is_link=True,
                            label="Voir les affinités",
                            form_action=
                            f"/affinity/{hapic_data.path.character_id}",
                        ),
                    ],
                )

        items = []

        # FIXME BS: Must be in presence of director to request become member
        if not relation:
            items.extend([
                Part(
                    is_link=True,
                    form_action=(
                        f"/affinity/{hapic_data.path.character_id}"
                        f"/edit-relation/{hapic_data.path.affinity_id}"
                        f"?request=1"),
                    label="Exprimer le souhait de devenir membre",
                ),
                Part(
                    is_link=True,
                    form_action=(
                        f"/affinity/{hapic_data.path.character_id}"
                        f"/edit-relation/{hapic_data.path.affinity_id}"
                        f"?request=1&fighter=1"),
                    label=
                    "Exprimer le souhait de devenir membre et de me battre avec eux",
                ),
                Part(
                    is_link=True,
                    form_action=(
                        f"/affinity/{hapic_data.path.character_id}"
                        f"/edit-relation/{hapic_data.path.affinity_id}"
                        f"?request=0&fighter=1"),
                    label="Me battre pour eux",
                ),
            ])
        else:
            if not relation.request:
                if not relation.fighter:
                    items.append(
                        Part(
                            is_link=True,
                            form_action=(
                                f"/affinity/{hapic_data.path.character_id}"
                                f"/edit-relation/{hapic_data.path.affinity_id}"
                                f"?request=1&fighter=1"),
                            label=
                            "Exprimer le souhait de devenir membre et de me battre pour elle",
                        ))
                else:
                    items.append(
                        Part(
                            is_link=True,
                            form_action=(
                                f"/affinity/{hapic_data.path.character_id}"
                                f"/edit-relation/{hapic_data.path.affinity_id}"
                                f"?request=1"),
                            label="Exprimer le souhait de devenir membre",
                        ))
            else:
                items.append(
                    Part(
                        is_link=True,
                        form_action=(
                            f"/affinity/{hapic_data.path.character_id}"
                            f"/edit-relation/{hapic_data.path.affinity_id}"
                            f"?request=0"),
                        label="Ne plus demander à être membre",
                    ))
            if relation.accepted:
                items.append(
                    Part(
                        is_link=True,
                        form_action=(
                            f"/affinity/{hapic_data.path.character_id}"
                            f"/edit-relation/{hapic_data.path.affinity_id}"
                            f"?rejected=1"),
                        label="Quitter cette affinité",
                    ))
            if relation.fighter:
                items.append(
                    Part(
                        is_link=True,
                        form_action=(
                            f"/affinity/{hapic_data.path.character_id}"
                            f"/edit-relation/{hapic_data.path.affinity_id}"
                            f"?fighter=0"),
                        label="Ne plus se battre pour cette affinité",
                    ))
            else:
                items.append(
                    Part(
                        is_link=True,
                        form_action=(
                            f"/affinity/{hapic_data.path.character_id}"
                            f"/edit-relation/{hapic_data.path.affinity_id}"
                            f"?fighter=1"),
                        label="Me battre pour cette affinité",
                    ))

        return Description(
            title=affinity.name,
            items=items,
            footer_links=[
                Part(is_link=True,
                     go_back_zone=True,
                     label="Retourner à l'écran de déplacements"),
                Part(
                    is_link=True,
                    label=f"Voir la fiche de {affinity.name}",
                    form_action=
                    f"/affinity/{hapic_data.path.character_id}/see/{affinity.id}",
                    classes=["primary"],
                ),
                Part(
                    is_link=True,
                    label="Voir les affinités",
                    form_action=f"/affinity/{hapic_data.path.character_id}",
                ),
            ],
        )
예제 #8
0
파일: take.py 프로젝트: coolkat64/rolling
    def perform(self, character: "CharacterModel",
                with_character: "CharacterModel",
                input_: TakeFromModel) -> Description:
        if input_.take_stuff_id is not None:
            stuff: StuffModel = self._kernel.stuff_lib.get_stuff(
                input_.take_stuff_id)
            likes_this_stuff = self._kernel.stuff_lib.get_carried_by(
                with_character.id,
                exclude_crafting=False,
                stuff_id=stuff.stuff_id)

            if input_.take_stuff_quantity is None:
                if len(likes_this_stuff) > 1:
                    return Description(
                        title=f"Prendre {stuff.name} sur {with_character.name}",
                        items=[
                            Part(
                                is_form=True,
                                form_values_in_query=True,
                                form_action=self._get_url(
                                    character, with_character, input_),
                                submit_label="Prendre",
                                items=[
                                    Part(
                                        label="Quantité ?",
                                        type_=Type.NUMBER,
                                        name="take_stuff_quantity",
                                        default_value=str(
                                            len(likes_this_stuff)),
                                    )
                                ],
                            )
                        ],
                        can_be_back_url=True,
                    )
                input_.take_stuff_quantity = 1

            for i in range(input_.take_stuff_quantity):
                self._kernel.stuff_lib.set_carried_by(likes_this_stuff[i].id,
                                                      character.id)

        if input_.take_resource_id is not None:
            resource_description = self._kernel.game.config.resources[
                input_.take_resource_id]
            carried_resource = self._kernel.resource_lib.get_one_carried_by(
                with_character.id, input_.take_resource_id)

            if input_.take_resource_quantity is None:
                unit_str = self._kernel.translation.get(
                    resource_description.unit)
                return Description(
                    title=
                    f"Prendre {resource_description.name} sur {with_character.name}",
                    items=[
                        Part(
                            is_form=True,
                            form_values_in_query=True,
                            form_action=self._get_url(character,
                                                      with_character, input_),
                            submit_label="Prendre",
                            items=[
                                Part(
                                    label=f"Quantité ({unit_str}) ?",
                                    type_=Type.NUMBER,
                                    name="take_resource_quantity",
                                    default_value=str(
                                        carried_resource.quantity),
                                )
                            ],
                        )
                    ],
                    can_be_back_url=True,
                )
            self._kernel.resource_lib.reduce_carried_by(
                character_id=with_character.id,
                resource_id=input_.take_resource_id,
                quantity=input_.take_resource_quantity,
            )
            self._kernel.resource_lib.add_resource_to(
                character_id=character.id,
                resource_id=input_.take_resource_id,
                quantity=input_.take_resource_quantity,
            )

        return self._get_take_something_description(character, with_character,
                                                    input_)
예제 #9
0
    async def new(self, request: Request,
                  hapic_data: HapicData) -> Description:
        try:
            data = await request.json()
        except JSONDecodeError:
            data = {}

        if data.get("name"):
            affinity_doc = self._kernel.affinity_lib.create(
                name=data["name"],
                join_type=AffinityJoinType.ONE_CHIEF_ACCEPT,
                direction_type=AffinityDirectionType.ONE_DIRECTOR,
                commit=True,
            )
            self._kernel.affinity_lib.join(
                character_id=hapic_data.path.character_id,
                affinity_id=affinity_doc.id,
                accepted=True,
                status_id=CHIEF_STATUS[0],
                fighter=True,
                commit=True,
            )
            return Description(
                title="Affinités créée",
                items=[Part(text="Et vous en êtes le chef")],
                footer_links=[
                    Part(is_link=True,
                         go_back_zone=True,
                         label="Retourner à l'écran de déplacements"),
                    Part(
                        is_link=True,
                        label=f"Voir la fiche de {affinity_doc.name}",
                        form_action=
                        f"/affinity/{hapic_data.path.character_id}/see/{affinity_doc.id}",
                        classes=["primary"],
                    ),
                    Part(
                        is_link=True,
                        label="Voir les affinités",
                        form_action=f"/affinity/{hapic_data.path.character_id}",
                    ),
                ],
            )

        return Description(
            title="Créer une affinité",
            items=[
                Part(
                    is_form=True,
                    form_action=f"/affinity/{hapic_data.path.character_id}/new",
                    items=[Part(label="Nom", name="name", type_=Type.STRING)],
                )
            ],
            footer_links=[
                Part(
                    is_link=True,
                    label="Retour aux affinités",
                    form_action=f"/affinity/{hapic_data.path.character_id}",
                )
            ],
        )
예제 #10
0
    async def start(self, request: Request, hapic_data: HapicData) -> Description:
        character_doc = self._kernel.character_lib.get_document(hapic_data.path.character_id)
        zone_characters = self._kernel.character_lib.get_zone_players(
            row_i=character_doc.world_row_i,
            col_i=character_doc.world_col_i,
            exclude_ids=[hapic_data.path.character_id],
        )

        try:
            data = await request.json()
            if data.get("message"):
                selected_character_ids = [c.id for c in zone_characters if data.get(c.id) == "on"]
                if not selected_character_ids:
                    return Description(
                        title="Démarrer une nouvelle conversation",
                        items=[
                            Part(text="Vous devez choisir au moins un personnage"),
                            Part(
                                is_link=True,
                                label="Retour",
                                form_action=f"/conversation/{hapic_data.path.character_id}/start",
                            ),
                            Part(
                                is_link=True,
                                go_back_zone=True,
                                label="Retourner à l'écran de déplacements",
                            ),
                        ],
                    )

                conversation_id = self._kernel.message_lib.add_conversation_message(
                    author_id=hapic_data.path.character_id,
                    subject=data.get("subject", "Une conversation"),
                    message=data["message"],
                    concerned=selected_character_ids,
                )
                return Description(
                    redirect=f"/conversation/{hapic_data.path.character_id}/read/{conversation_id}"
                )

        except JSONDecodeError:
            pass  # no json (i guess)

        if not zone_characters:
            return Description(
                title="Démarrer une nouvelle conversation",
                items=[
                    Part(text="Il n'y a personne ici avec qui converser"),
                    Part(
                        is_link=True, go_back_zone=True, label="Retourner à l'écran de déplacements"
                    ),
                    Part(
                        is_link=True,
                        label="Retourner aux conversations",
                        form_action=f"/conversation/{hapic_data.path.character_id}",
                    ),
                ],
            )

        character_parts = []
        for zone_character in zone_characters:
            character_parts.append(
                Part(
                    label=zone_character.name,
                    value="on",
                    is_checkbox=True,
                    name=zone_character.id,
                    # FIXME BS NOW: test it
                    checked=zone_character.id == hapic_data.query.with_character_id,
                )
            )

        return Description(
            title="Démarrer une nouvelle conversation",
            items=[
                Part(
                    text="Vous devez choisir les personnages avec qui entretenir cette conversation"
                ),
                Part(
                    is_form=True,
                    form_action=f"/conversation/{hapic_data.path.character_id}/start",
                    items=character_parts
                    + [
                        Part(label="Choisissez un titre", type_=Type.STRING, name="subject"),
                        Part(label="Saisissez votre élocuction", type_=Type.STRING, name="message"),
                    ],
                ),
            ],
            footer_links=[
                Part(is_link=True, go_back_zone=True, label="Retourner à l'écran de déplacements"),
                Part(
                    is_link=True,
                    label="Retourner aux conversations",
                    form_action=f"/conversation/{hapic_data.path.character_id}",
                ),
            ],
        )
예제 #11
0
파일: craft.py 프로젝트: coolkat64/rolling
    def perform(
        self, character: "CharacterModel", stuff: "StuffModel", input_: ContinueStuffModel
    ) -> Description:
        bonus = character.get_skill_value("intelligence") + character.get_skill_value("crafts")
        bonus_divider = max(1.0, (bonus * 2) / DEFAULT_MAXIMUM_SKILL)
        remain_ap = stuff.ap_required - stuff.ap_spent
        remain_ap_for_character = remain_ap / bonus_divider

        if not input_.ap:
            return Description(
                title=f"Continuer de travailler sur {stuff.name}",
                items=[
                    Part(
                        is_form=True,
                        form_values_in_query=True,
                        form_action=get_with_stuff_action_url(
                            character_id=character.id,
                            action_type=ActionType.CONTINUE_STUFF_CONSTRUCTION,
                            query_params={},
                            action_description_id=self._description.id,
                            stuff_id=stuff.id,
                        ),
                        items=[
                            Part(
                                text=f"Il reste {round(remain_ap, 3)} PA à passer ({round(remain_ap_for_character, 3)} avec vos bonus)"
                            ),
                            Part(
                                label=f"Combien de points d'actions dépenser ?",
                                type_=Type.NUMBER,
                                name="ap",
                            ),
                        ],
                    )
                ],
            )

        consume_ap = min(remain_ap, input_.ap * bonus_divider)
        stuff_doc = self._kernel.stuff_lib.get_stuff_doc(stuff.id)
        stuff_doc.ap_spent = float(stuff_doc.ap_spent) + consume_ap
        self._kernel.character_lib.reduce_action_points(character.id, consume_ap, commit=False)

        if stuff_doc.ap_spent >= stuff_doc.ap_required:
            stuff_doc.under_construction = False
            title = f"Construction de {stuff.name} terminé"
        else:
            title = f"Construction de {stuff.name} avancé"

        self._kernel.server_db_session.commit()
        return Description(
            title=title,
            footer_links=[
                Part(is_link=True, go_back_zone=True, label="Retourner à l'écran de déplacements"),
                Part(
                    is_link=True,
                    label="Voir l'objet commencé",
                    form_action=DESCRIBE_LOOK_AT_STUFF_URL.format(
                        character_id=character.id, stuff_id=stuff_doc.id
                    ),
                    classes=["primary"],
                ),
            ],
            force_back_url=f"/_describe/character/{character.id}/on_place_actions",
        )
예제 #12
0
파일: craft.py 프로젝트: coolkat64/rolling
    def perform(self, character: "CharacterModel", input_: BeginStuffModel) -> Description:
        if not input_.description:
            require_txts = []
            for consume in self._description.properties["consume"]:
                if "resource" in consume:
                    resource_id = consume["resource"]
                    resource_description = self._kernel.game.config.resources[resource_id]
                    quantity_str = quantity_to_str(
                        consume["quantity"], resource_description.unit, self._kernel
                    )
                    require_txts.append(f"{quantity_str} de {resource_description.name}")

                elif "stuff" in consume:
                    stuff_id = consume["stuff"]
                    stuff_properties = self._kernel.game.stuff_manager.get_stuff_properties_by_id(
                        stuff_id
                    )
                    require_txts.append(f"{consume['quantity']} de {stuff_properties.name}")

            return Description(
                title=f"Commencer {self._description.name}",
                items=[
                    Part(
                        is_form=True,
                        form_values_in_query=True,
                        form_action=get_character_action_url(
                            character_id=character.id,
                            action_type=ActionType.BEGIN_STUFF_CONSTRUCTION,
                            query_params={},
                            action_description_id=self._description.id,
                        ),
                        items=[Part(text="Consommera :")]
                        + [Part(text=txt) for txt in require_txts]
                        + [
                            Part(
                                label=f"Vous pouvez fournir une description de l'objet",
                                type_=Type.STRING,
                                name="description",
                                default_value=self._description.properties["default_description"],
                            )
                        ],
                    )
                ],
            )

        for consume in self._description.properties["consume"]:
            if "resource" in consume:
                resource_id = consume["resource"]
                self._kernel.resource_lib.reduce_carried_by(
                    character.id,
                    resource_id=resource_id,
                    quantity=consume["quantity"],
                    commit=False,
                )

            elif "stuff" in consume:
                stuff_id = consume["stuff"]
                carried_stuffs = self._kernel.stuff_lib.get_carried_by(
                    character.id, stuff_id=stuff_id
                )
                for i in range(consume["quantity"]):
                    self._kernel.stuff_lib.destroy(carried_stuffs[i].id, commit=False)

        stuff_id = self._description.properties["produce_stuff_id"]
        stuff_properties = self._kernel.game.stuff_manager.get_stuff_properties_by_id(stuff_id)
        stuff_doc = self._kernel.stuff_lib.create_document_from_stuff_properties(
            properties=stuff_properties,
            world_row_i=character.world_row_i,
            world_col_i=character.world_col_i,
            zone_row_i=character.zone_row_i,
            zone_col_i=character.zone_col_i,
        )
        stuff_doc.description = input_.description or ""
        stuff_doc.carried_by_id = character.id
        stuff_doc.ap_spent = 0.0
        stuff_doc.ap_required = self._description.properties["craft_ap"]
        stuff_doc.under_construction = True
        self._kernel.stuff_lib.add_stuff(stuff_doc, commit=False)
        self._kernel.character_lib.reduce_action_points(
            character.id, cost=self.get_cost(character), commit=False
        )
        self._kernel.server_db_session.commit()

        return Description(
            title=f"{stuff_properties.name} commencé",
            footer_links=[
                Part(is_link=True, go_back_zone=True, label="Retourner à l'écran de déplacements"),
                Part(
                    is_link=True,
                    label="Voir l'objet commencé",
                    form_action=DESCRIBE_LOOK_AT_STUFF_URL.format(
                        character_id=character.id, stuff_id=stuff_doc.id
                    ),
                    classes=["primary"],
                ),
            ],
            force_back_url=f"/_describe/character/{character.id}/on_place_actions",
        )
예제 #13
0
파일: mix.py 프로젝트: coolkat64/rolling
    def perform(self, character: "CharacterModel", resource_id: str,
                input_: input_model) -> Description:
        base_cost = self.get_cost(character, resource_id=resource_id)
        resource_mix_description = self._kernel.game.config.resource_mixs[
            input_.resource_mix_id]
        unit_name = self._kernel.translation.get(
            resource_mix_description.produce_resource.unit)
        cost_per_unit = resource_mix_description.cost

        if input_.quantity is None:
            required = ", ".join([
                f"{round(r.coeff * 100)}% {r.resource.name}"
                for r in resource_mix_description.required_resources
            ])
            return Description(
                title=f"Faire {resource_mix_description.produce_resource.name}",
                items=[
                    Part(
                        is_form=True,
                        form_values_in_query=True,
                        form_action=get_with_resource_action_url(
                            character_id=character.id,
                            action_type=ActionType.MIX_RESOURCES,
                            resource_id=resource_id,
                            query_params=self.input_model_serializer.dump(
                                input_),
                            action_description_id=self._description.id,
                        ),
                        items=[
                            Part(
                                label=
                                f"Quantité en {unit_name} (coût: {base_cost} + {cost_per_unit} par {unit_name}, avec {required}) ?",
                                type_=Type.NUMBER,
                                name="quantity",
                            )
                        ],
                    )
                ],
            )

        # Make mix
        for required_resource in resource_mix_description.required_resources:
            required_quantity = required_resource.coeff * input_.quantity
            self._kernel.resource_lib.reduce_carried_by(
                character.id,
                required_resource.resource.id,
                required_quantity,
                commit=False)

        self._kernel.resource_lib.add_resource_to(
            character_id=character.id,
            resource_id=resource_mix_description.produce_resource.id,
            quantity=input_.quantity,
            commit=False,
        )
        self._kernel.character_lib.reduce_action_points(
            character_id=character.id,
            cost=self.get_cost(character,
                               resource_id=resource_id,
                               input_=input_),
            commit=False,
        )
        self._kernel.server_db_session.commit()

        return Description(
            title=f"{input_.quantity} "
            f"{resource_mix_description.produce_resource.name} {unit_name} produits",
            footer_links=[
                Part(is_link=True,
                     go_back_zone=True,
                     label="Retourner à l'écran de déplacements"),
                Part(
                    is_link=True,
                    label="Voir l'inventaire",
                    form_action=
                    f"/_describe/character/{character.id}/inventory",
                    classes=["primary"],
                ),
            ],
        )
예제 #14
0
    def perform(
        self,
        character: "CharacterModel",
        with_character: "CharacterModel",
        input_: ProposeTeachKnowledgeModel,
    ) -> Description:
        knowledge_description = self._kernel.game.config.knowledge[
            input_.knowledge_id]
        if input_.ap is None:
            max_turns = self._kernel.game.config.max_action_propose_turns
            return Description(
                title=
                f"Enseigner {knowledge_description.name} à {with_character.name}",
                items=[
                    Part(
                        is_form=True,
                        form_values_in_query=True,
                        form_action=self._get_url(character, with_character,
                                                  input_),
                        items=[
                            Part(
                                label=
                                f"Passer combien de points d'actions sur ce cours ?",
                                type_=Type.NUMBER,
                                name="ap",
                            ),
                            Part(
                                label=(
                                    f"Proposition valable combien de tours "
                                    f"(max {max_turns}, en cours compris) ?"),
                                type_=Type.NUMBER,
                                name="expire",
                                default_value="1",
                            ),
                        ],
                    )
                ],
            )

        pending_action_document = self._kernel.action_factory.create_pending_action(
            action_scope=ActionScope.WITH_CHARACTER,
            action_type=ActionType.TEACH_KNOWLEDGE,
            action_description_id=ActionType.TEACH_KNOWLEDGE.value,
            character_id=character.id,
            with_character_id=with_character.id,
            parameters=TeachKnowledgeAction.input_model_serializer.dump(
                TeachKnowledgeModel(knowledge_id=input_.knowledge_id,
                                    ap=input_.ap)),
            expire_at_turn=self._kernel.universe_lib.get_last_state().turn +
            (input_.expire - 1),
            suggested_by=character.id,
            name=(f"Prendre un cours de {knowledge_description.name} avec"
                  f" {character.name} pendant {input_.ap} points d'actions"),
            delete_after_first_perform=True,
        )
        self._kernel.action_factory.add_pending_action_authorization(
            pending_action_id=pending_action_document.id,
            authorized_character_id=with_character.id)

        return Description(
            title="Proposition effectué",
            footer_links=[
                Part(is_link=True,
                     go_back_zone=True,
                     label="Retourner à l'écran de déplacements")
            ],
        )