valentina-python-client 3.4.0__tar.gz → 3.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/PKG-INFO +1 -1
  2. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/pyproject.toml +1 -1
  3. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/pyproject.toml.orig +1 -1
  4. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/__init__.py +1 -1
  5. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/character_traits.py +12 -23
  6. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/characters.py +10 -22
  7. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/options.py +3 -3
  8. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/constants.py +0 -1
  9. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/__init__.py +0 -2
  10. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/character_trait.py +28 -56
  11. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/characters.py +1 -1
  12. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/character_traits.py +11 -18
  13. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/characters.py +9 -17
  14. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/options.py +3 -3
  15. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/testing/__init__.py +0 -2
  16. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/testing/_factories.py +18 -38
  17. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/testing/_router.py +0 -3
  18. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/testing/_routes.py +5 -5
  19. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/validate_constants.py +0 -1
  20. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/LICENSE +0 -0
  21. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/README.md +0 -0
  22. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_codegen.py +0 -0
  23. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/__init__.py +0 -0
  24. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/client.py +0 -0
  25. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/registry.py +0 -0
  26. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/__init__.py +0 -0
  27. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/_audit_params.py +0 -0
  28. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/base.py +0 -0
  29. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/campaign_book_chapters.py +0 -0
  30. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/campaign_books.py +0 -0
  31. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/campaigns.py +0 -0
  32. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/character_autogen.py +0 -0
  33. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/character_blueprint.py +0 -0
  34. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/companies.py +0 -0
  35. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/developers.py +0 -0
  36. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/dicerolls.py +0 -0
  37. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/dictionary.py +0 -0
  38. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/global_admin.py +0 -0
  39. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/identity.py +0 -0
  40. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/system.py +0 -0
  41. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/user_lookup.py +0 -0
  42. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/services/users.py +0 -0
  43. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/testing/__init__.py +0 -0
  44. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/_sync/testing/_client.py +0 -0
  45. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/client.py +0 -0
  46. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/config.py +0 -0
  47. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/endpoints.py +0 -0
  48. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/exceptions.py +0 -0
  49. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/audit_logs.py +0 -0
  50. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/books.py +0 -0
  51. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/campaigns.py +0 -0
  52. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/chapters.py +0 -0
  53. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/character_autogen.py +0 -0
  54. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/character_blueprint.py +0 -0
  55. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/companies.py +0 -0
  56. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/developers.py +0 -0
  57. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/diceroll.py +0 -0
  58. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/dictionary.py +0 -0
  59. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/full_sheet.py +0 -0
  60. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/global_admin.py +0 -0
  61. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/pagination.py +0 -0
  62. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/shared.py +0 -0
  63. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/system.py +0 -0
  64. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/user_lookup.py +0 -0
  65. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/models/users.py +0 -0
  66. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/py.typed +0 -0
  67. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/registry.py +0 -0
  68. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/__init__.py +0 -0
  69. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/_audit_params.py +0 -0
  70. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/base.py +0 -0
  71. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/campaign_book_chapters.py +0 -0
  72. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/campaign_books.py +0 -0
  73. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/campaigns.py +0 -0
  74. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/character_autogen.py +0 -0
  75. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/character_blueprint.py +0 -0
  76. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/companies.py +0 -0
  77. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/developers.py +0 -0
  78. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/dicerolls.py +0 -0
  79. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/dictionary.py +0 -0
  80. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/global_admin.py +0 -0
  81. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/identity.py +0 -0
  82. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/system.py +0 -0
  83. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/user_lookup.py +0 -0
  84. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/services/users.py +0 -0
  85. {valentina_python_client-3.4.0 → valentina_python_client-3.5.0}/src/vclient/testing/_client.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: valentina-python-client
3
- Version: 3.4.0
3
+ Version: 3.5.0
4
4
  Summary: Async Python client library for the Valentina Noir API
5
5
  Author: Nate Landau
6
6
  Author-email: Nate Landau <github@natenate.org>
@@ -15,7 +15,7 @@ description = "Async Python client library for the Valentina Noir API"
15
15
  name = "valentina-python-client"
16
16
  readme = "README.md"
17
17
  requires-python = ">=3.13"
18
- version = "3.4.0"
18
+ version = "3.5.0"
19
19
 
20
20
  [[project.authors]]
21
21
  name = "Nate Landau"
@@ -17,7 +17,7 @@
17
17
  name = "valentina-python-client"
18
18
  readme = "README.md"
19
19
  requires-python = ">=3.13"
20
- version = "3.4.0"
20
+ version = "3.5.0"
21
21
 
22
22
  [project.optional-dependencies]
23
23
  testing = ["polyfactory>=3.3.0"]
@@ -116,4 +116,4 @@ __all__ = (
116
116
  "users_service",
117
117
  )
118
118
 
119
- __version__ = "3.4.0"
119
+ __version__ = "3.5.0"
@@ -5,7 +5,7 @@ from collections.abc import Iterator
5
5
  from typing import TYPE_CHECKING
6
6
 
7
7
  from vclient._sync.services.base import SyncBaseService
8
- from vclient.constants import DEFAULT_PAGE_LIMIT, DamageType, TrackerAction, TraitModifyCurrency
8
+ from vclient.constants import DEFAULT_PAGE_LIMIT, TrackerAction, TraitModifyCurrency
9
9
  from vclient.endpoints import Endpoints
10
10
  from vclient.models import (
11
11
  _TRACKER_ADAPTER,
@@ -407,7 +407,7 @@ class SyncCharacterTraitsService(SyncBaseService):
407
407
  character_trait_id: The ID of the character trait.
408
408
 
409
409
  Returns:
410
- A CounterTracker, DamageTracker, or StainsTracker. Switch on ``type``.
410
+ A CounterTracker or StainsTracker. Switch on ``type``.
411
411
 
412
412
  Raises:
413
413
  NotFoundError: If the trait has no tracker for the character's game version.
@@ -425,16 +425,15 @@ class SyncCharacterTraitsService(SyncBaseService):
425
425
  ) -> Tracker:
426
426
  """Replace the full state of a trait tracker, such as to correct a mistake.
427
427
 
428
- Send only the fields for the tracker's type: ``current`` for counters (required),
429
- ``superficial`` and ``aggravated`` for damage tracks, ``stains`` for stains. Omitted
430
- fields reset to 0, so an empty request clears a damage or stains tracker. Use
428
+ Send only the field for the tracker's type: ``current`` for counters (required) or
429
+ ``stains`` for stains. An empty request clears a stains tracker. Use
431
430
  ``apply_tracker_action`` for in-play changes instead.
432
431
 
433
432
  Args:
434
433
  character_trait_id: The ID of the character trait.
435
434
  request: A TrackerStateSet model, OR pass fields as keyword arguments.
436
435
  **kwargs: Fields for TrackerStateSet if request is not provided.
437
- Accepts: current, superficial, aggravated, stains (int >= 0).
436
+ Accepts: current, stains (int >= 0).
438
437
 
439
438
  Returns:
440
439
  The updated tracker.
@@ -442,7 +441,7 @@ class SyncCharacterTraitsService(SyncBaseService):
442
441
  Raises:
443
442
  NotFoundError: If the trait has no tracker for the character's game version.
444
443
  AuthorizationError: If you are not the character's player or a storyteller.
445
- RequestValidationError: If a value is negative.
444
+ RequestValidationError: If a value is negative or a field is unknown.
446
445
  ValidationError: If a field does not fit the tracker type, a counter has no
447
446
  ``current``, or a value exceeds the tracker size.
448
447
  """
@@ -456,25 +455,17 @@ class SyncCharacterTraitsService(SyncBaseService):
456
455
  return _TRACKER_ADAPTER.validate_python(response.json())
457
456
 
458
457
  def apply_tracker_action(
459
- self,
460
- character_trait_id: str,
461
- action: TrackerAction,
462
- *,
463
- amount: int = 1,
464
- damage_type: DamageType | None = None,
458
+ self, character_trait_id: str, action: TrackerAction, *, amount: int = 1
465
459
  ) -> Tracker:
466
460
  """Apply one in-play action to a trait tracker, such as spending Willpower.
467
461
 
468
- The server applies the game rules for the character's game version. Which actions
469
- and damage types fit each tracker is listed in ``characters.TrackerRules`` from
470
- ``options.get_options()``. A STAINS response reports overflow into Willpower in
471
- ``willpower_damage_applied``.
462
+ The actions each tracker accepts are listed in
463
+ ``characters.TrackerRules[game_version][tracker.type]`` from ``options.get_options()``.
472
464
 
473
465
  Args:
474
466
  character_trait_id: The ID of the character trait.
475
467
  action: The action to apply.
476
468
  amount: How many points to apply. Must be at least 1.
477
- damage_type: The damage type for ``damage`` and ``heal`` on damage tracks.
478
469
 
479
470
  Returns:
480
471
  The updated tracker.
@@ -483,12 +474,10 @@ class SyncCharacterTraitsService(SyncBaseService):
483
474
  NotFoundError: If the trait has no tracker for the character's game version.
484
475
  AuthorizationError: If you are not the character's player or a storyteller.
485
476
  RequestValidationError: If ``amount`` is less than 1.
486
- ValidationError: If the action or damage type does not fit the tracker, a
487
- damage type is missing or not allowed, or a spend exceeds the current value.
477
+ ValidationError: If the action does not fit the tracker or a spend exceeds the
478
+ current value.
488
479
  """
489
- body = self._validate_request(
490
- _TrackerAction, action=action, amount=amount, damage_type=damage_type
491
- )
480
+ body = self._validate_request(_TrackerAction, action=action, amount=amount)
492
481
  response = self._post(
493
482
  self._format_endpoint(
494
483
  Endpoints.CHARACTER_TRAIT_TRACKER_ACTIONS, character_trait_id=character_trait_id
@@ -12,7 +12,6 @@ from vclient.constants import (
12
12
  CharacterInclude,
13
13
  CharacterStatus,
14
14
  CharacterType,
15
- DamageType,
16
15
  TrackerAction,
17
16
  )
18
17
  from vclient.endpoints import Endpoints
@@ -905,15 +904,14 @@ class SyncCharactersService(SyncBaseService):
905
904
  ) -> Health:
906
905
  """Replace a character's full health state, such as to correct a mistake.
907
906
 
908
- Every field is sent, so omitted fields reset to 0. V4 uses ``bashing``,
909
- ``lethal``, and ``aggravated``; V5 uses ``superficial`` and ``aggravated``.
910
- ``extra_levels`` applies to both. Use ``apply_health_action`` for in-play changes.
907
+ Every field is sent, so omitted fields reset to 0. Use ``apply_health_action`` for
908
+ in-play changes.
911
909
 
912
910
  Args:
913
911
  character_id: The ID of the character.
914
912
  request: A HealthStateSet model, OR pass fields as keyword arguments.
915
913
  **kwargs: Fields for HealthStateSet if request is not provided.
916
- Accepts: extra_levels, superficial, aggravated, bashing, lethal (int >= 0).
914
+ Accepts: extra_levels, damage (int >= 0).
917
915
 
918
916
  Returns:
919
917
  The updated Health.
@@ -921,9 +919,8 @@ class SyncCharactersService(SyncBaseService):
921
919
  Raises:
922
920
  NotFoundError: If the character does not exist or has no health track.
923
921
  AuthorizationError: If you are not the character's player or a storyteller.
924
- RequestValidationError: If a value is negative.
925
- ValidationError: If a nonzero field is not used by the game version, or the
926
- marks exceed the track size.
922
+ RequestValidationError: If a value is negative or a field is unknown.
923
+ ValidationError: If the damage exceeds the track size.
927
924
  """
928
925
  body = request if request is not None else self._validate_request(HealthStateSet, **kwargs)
929
926
  response = self._put(
@@ -933,24 +930,17 @@ class SyncCharactersService(SyncBaseService):
933
930
  return Health.model_validate(response.json())
934
931
 
935
932
  def apply_health_action(
936
- self,
937
- character_id: str,
938
- action: TrackerAction,
939
- *,
940
- amount: int = 1,
941
- damage_type: DamageType | None = None,
933
+ self, character_id: str, action: TrackerAction, *, amount: int = 1
942
934
  ) -> Health:
943
935
  """Apply one in-play action to a character's health, such as taking damage.
944
936
 
945
- Health accepts ``damage``, ``heal``, and ``reset``. V4 damage types are
946
- ``BASHING``, ``LETHAL``, and ``AGGRAVATED``; V5 damage types are ``SUPERFICIAL``
947
- and ``AGGRAVATED``. The server applies overflow and upgrade rules.
937
+ Health accepts ``damage``, ``heal``, and ``reset``. Damage past a full track and
938
+ healing past 0 are dropped.
948
939
 
949
940
  Args:
950
941
  character_id: The ID of the character.
951
942
  action: The action to apply.
952
943
  amount: How many points to apply. Must be at least 1.
953
- damage_type: The damage type for ``damage`` and ``heal``.
954
944
 
955
945
  Returns:
956
946
  The updated Health.
@@ -959,11 +949,9 @@ class SyncCharactersService(SyncBaseService):
959
949
  NotFoundError: If the character does not exist or has no health track.
960
950
  AuthorizationError: If you are not the character's player or a storyteller.
961
951
  RequestValidationError: If ``amount`` is less than 1.
962
- ValidationError: If the action or damage type does not fit the game version.
952
+ ValidationError: If the action does not apply to health.
963
953
  """
964
- body = self._validate_request(
965
- _TrackerAction, action=action, amount=amount, damage_type=damage_type
966
- )
954
+ body = self._validate_request(_TrackerAction, action=action, amount=amount)
967
955
  response = self._post(
968
956
  self._format_endpoint(Endpoints.CHARACTER_HEALTH_ACTIONS, character_id=character_id),
969
957
  json=body.model_dump(exclude_none=True, mode="json"),
@@ -36,9 +36,9 @@ class SyncOptionsService(SyncBaseService):
36
36
  """Retrieve all options and enumerations for the api.
37
37
 
38
38
  Most values are lists of enum values. ``characters.TrackerRules`` is a nested map
39
- ``{game_version: {tracker_key: {"actions": [...], "damage_types": [...]}}}`` where
40
- ``tracker_key`` is a tracker type or ``HEALTH``. Use it to choose which tracker
41
- actions and damage types to offer instead of hardcoding them.
39
+ ``{game_version: {tracker_type: {"actions": [...]}}}``. Health is keyed by its
40
+ ``type``, ``DAMAGE``. Use it to choose which tracker actions to offer instead of
41
+ hardcoding them.
42
42
 
43
43
  Returns:
44
44
  A dictionary of options and enumerations for the api.
@@ -106,4 +106,3 @@ BlueprintTraitOrderBy = Literal["NAME", "SHEET"]
106
106
  TraitModifyCurrency = Literal["XP", "STARTING_POINTS", "NO_COST"]
107
107
  TrackerType = Literal["COUNTER", "DAMAGE", "STAINS"]
108
108
  TrackerAction = Literal["spend", "gain", "damage", "heal", "add_stain", "remove_stain", "reset"]
109
- DamageType = Literal["SUPERFICIAL", "AGGRAVATED", "BASHING", "LETHAL"]
@@ -51,7 +51,6 @@ from .character_trait import (
51
51
  CharacterTraitSpecialtyUpdate,
52
52
  CharacterTraitValueOptionsResponse,
53
53
  CounterTracker,
54
- DamageTracker,
55
54
  Health,
56
55
  HealthLevel,
57
56
  HealthStateSet,
@@ -213,7 +212,6 @@ __all__ = [
213
212
  "CompanyUpdate",
214
213
  "CounterTracker",
215
214
  "CreateAutogenerateDTO",
216
- "DamageTracker",
217
215
  "Developer",
218
216
  "DeveloperCompanyPermission",
219
217
  "DeveloperCreate",
@@ -3,9 +3,9 @@
3
3
  from datetime import datetime
4
4
  from typing import Annotated, Literal
5
5
 
6
- from pydantic import BaseModel, Field, TypeAdapter
6
+ from pydantic import BaseModel, ConfigDict, Field, TypeAdapter
7
7
 
8
- from vclient.constants import DamageType, TrackerAction, TraitModifyCurrency
8
+ from vclient.constants import TrackerAction, TraitModifyCurrency
9
9
 
10
10
  from .shared import Trait
11
11
 
@@ -20,77 +20,52 @@ class CharacterTraitSpecialty(BaseModel):
20
20
 
21
21
 
22
22
  class HealthLevel(BaseModel):
23
- """One V4 health level with its dice penalty and the damage marked on it."""
23
+ """One V4 health level and whether it is marked."""
24
24
 
25
25
  name: str
26
- penalty: int | None = Field(
27
- default=None, description="Dice pool penalty at this level. None for Incapacitated."
28
- )
29
- mark: DamageType | None = Field(
30
- default=None, description="Damage marked on this level, or None when empty."
26
+ marked: bool | None = Field(
27
+ default=None, description="Whether the level is marked. None only from older API versions."
31
28
  )
32
29
 
33
30
 
34
31
  class CounterTracker(BaseModel):
35
- """Tracker for a trait whose current value is spent and regained in play, such as V4 Willpower."""
32
+ """Tracker for a trait whose current value is spent and regained in play, such as Willpower."""
36
33
 
37
34
  type: Literal["COUNTER"] = "COUNTER"
38
35
  size: int = Field(..., description="Maximum, equal to the trait's value.")
39
36
  current: int = Field(..., description="Points currently available.")
40
37
 
41
38
 
42
- class DamageTracker(BaseModel):
43
- """Damage track used by V5 Willpower and by Health in both game versions.
44
-
45
- The V4-only fields (``bashing``, ``lethal``, ``levels``, ``current_penalty``) are ``None``
46
- for V5.
47
- """
48
-
49
- type: Literal["DAMAGE"] = "DAMAGE"
50
- size: int = Field(..., description="Number of boxes on the track.")
51
- superficial: int
52
- aggravated: int
53
- boxes: list[DamageType | None] = Field(
54
- default_factory=list,
55
- description="One entry per box in severity order, padded with None for empty boxes.",
56
- )
57
- is_impaired: bool
58
- bashing: int | None = None
59
- lethal: int | None = None
60
- levels: list[HealthLevel] | None = None
61
- current_penalty: int | None = Field(
62
- default=None,
63
- description="Dice pool penalty from the most severe marked V4 level. None on V5, and on V4 "
64
- "when Incapacitated is marked.",
65
- )
66
-
67
-
68
39
  class StainsTracker(BaseModel):
69
- """Tracker for V5 Humanity stains."""
40
+ """Tracker for V5 vampire Humanity stains."""
70
41
 
71
42
  type: Literal["STAINS"] = "STAINS"
72
43
  humanity: int
73
44
  stain_capacity: int = Field(..., description="Boxes left for stains, 10 minus Humanity.")
74
45
  stains: int
75
- is_impaired: bool
76
- willpower_damage_applied: int | None = Field(
77
- default=None,
78
- description="Stains that overflowed into Willpower damage. Set only on action responses.",
79
- )
80
46
 
81
47
 
82
48
  # In-play tracker state for a trait; pydantic picks the variant from ``type``.
83
- Tracker = Annotated[CounterTracker | DamageTracker | StainsTracker, Field(discriminator="type")]
49
+ Tracker = Annotated[CounterTracker | StainsTracker, Field(discriminator="type")]
84
50
 
85
51
  _TRACKER_ADAPTER: TypeAdapter[Tracker] = TypeAdapter(Tracker)
86
52
 
87
53
 
88
- class Health(DamageTracker):
89
- """A character's health track: a damage track plus V4 extra health levels."""
54
+ class Health(BaseModel):
55
+ """A character's health track: one damage count, plus named levels in V4."""
90
56
 
57
+ type: Literal["DAMAGE"] = "DAMAGE"
58
+ size: int = Field(..., description="Number of boxes on the track.")
59
+ damage: int | None = Field(
60
+ default=None,
61
+ description="Marked boxes. None only from API versions that report typed damage marks.",
62
+ )
91
63
  extra_levels: int = Field(
92
64
  default=0, description="Health levels added on top of the base track."
93
65
  )
66
+ levels: list[HealthLevel] | None = Field(
67
+ default=None, description="Named V4 health levels in track order. None for V5."
68
+ )
94
69
 
95
70
 
96
71
  class CharacterTrait(BaseModel):
@@ -114,28 +89,27 @@ class CharacterTrait(BaseModel):
114
89
  class TrackerStateSet(BaseModel):
115
90
  """Request model for setting a trait tracker's full state.
116
91
 
117
- Set only the fields for the tracker's type: ``current`` for counters (required),
118
- ``superficial`` and ``aggravated`` for damage tracks, ``stains`` for stains.
92
+ Set only the field for the tracker's type: ``current`` for counters (required) or
93
+ ``stains`` for stains. Unknown fields raise so a stale key fails instead of being dropped.
119
94
  """
120
95
 
96
+ model_config = ConfigDict(extra="forbid")
97
+
121
98
  current: int | None = Field(default=None, ge=0)
122
- superficial: int | None = Field(default=None, ge=0)
123
- aggravated: int | None = Field(default=None, ge=0)
124
99
  stains: int | None = Field(default=None, ge=0)
125
100
 
126
101
 
127
102
  class HealthStateSet(BaseModel):
128
103
  """Request model for setting a character's full health state.
129
104
 
130
- V4 uses ``bashing``, ``lethal``, and ``aggravated``; V5 uses ``superficial`` and
131
- ``aggravated``. ``extra_levels`` applies to both. Omitted fields reset to 0.
105
+ Omitted fields reset to 0. Unknown fields raise so a stale key fails instead of
106
+ silently clearing the track.
132
107
  """
133
108
 
109
+ model_config = ConfigDict(extra="forbid")
110
+
134
111
  extra_levels: int = Field(default=0, ge=0)
135
- superficial: int = Field(default=0, ge=0)
136
- aggravated: int = Field(default=0, ge=0)
137
- bashing: int = Field(default=0, ge=0)
138
- lethal: int = Field(default=0, ge=0)
112
+ damage: int = Field(default=0, ge=0)
139
113
 
140
114
 
141
115
  class _TrackerAction(BaseModel):
@@ -143,7 +117,6 @@ class _TrackerAction(BaseModel):
143
117
 
144
118
  action: TrackerAction
145
119
  amount: int = Field(default=1, ge=1)
146
- damage_type: DamageType | None = None
147
120
 
148
121
 
149
122
  class CharacterCreateTraitAssign(BaseModel):
@@ -273,7 +246,6 @@ __all__ = [
273
246
  "CharacterTraitValueOption",
274
247
  "CharacterTraitValueOptionsResponse",
275
248
  "CounterTracker",
276
- "DamageTracker",
277
249
  "Health",
278
250
  "HealthLevel",
279
251
  "HealthStateSet",
@@ -309,7 +309,7 @@ class CharacterCreate(BaseModel):
309
309
  )
310
310
  health: HealthStateSet | None = Field(
311
311
  default=None,
312
- description="Starting health marks. Omit for an unhurt character.",
312
+ description="Starting health damage. Omit for an unhurt character.",
313
313
  )
314
314
  vampire_attributes: VampireAttributesCreate | None = Field(
315
315
  default=None, description="Vampire-specific attributes."
@@ -3,7 +3,7 @@
3
3
  from collections.abc import AsyncIterator
4
4
  from typing import TYPE_CHECKING
5
5
 
6
- from vclient.constants import DEFAULT_PAGE_LIMIT, DamageType, TrackerAction, TraitModifyCurrency
6
+ from vclient.constants import DEFAULT_PAGE_LIMIT, TrackerAction, TraitModifyCurrency
7
7
  from vclient.endpoints import Endpoints
8
8
  from vclient.models import (
9
9
  _TRACKER_ADAPTER,
@@ -463,7 +463,7 @@ class CharacterTraitsService(BaseService):
463
463
  character_trait_id: The ID of the character trait.
464
464
 
465
465
  Returns:
466
- A CounterTracker, DamageTracker, or StainsTracker. Switch on ``type``.
466
+ A CounterTracker or StainsTracker. Switch on ``type``.
467
467
 
468
468
  Raises:
469
469
  NotFoundError: If the trait has no tracker for the character's game version.
@@ -484,16 +484,15 @@ class CharacterTraitsService(BaseService):
484
484
  ) -> Tracker:
485
485
  """Replace the full state of a trait tracker, such as to correct a mistake.
486
486
 
487
- Send only the fields for the tracker's type: ``current`` for counters (required),
488
- ``superficial`` and ``aggravated`` for damage tracks, ``stains`` for stains. Omitted
489
- fields reset to 0, so an empty request clears a damage or stains tracker. Use
487
+ Send only the field for the tracker's type: ``current`` for counters (required) or
488
+ ``stains`` for stains. An empty request clears a stains tracker. Use
490
489
  ``apply_tracker_action`` for in-play changes instead.
491
490
 
492
491
  Args:
493
492
  character_trait_id: The ID of the character trait.
494
493
  request: A TrackerStateSet model, OR pass fields as keyword arguments.
495
494
  **kwargs: Fields for TrackerStateSet if request is not provided.
496
- Accepts: current, superficial, aggravated, stains (int >= 0).
495
+ Accepts: current, stains (int >= 0).
497
496
 
498
497
  Returns:
499
498
  The updated tracker.
@@ -501,7 +500,7 @@ class CharacterTraitsService(BaseService):
501
500
  Raises:
502
501
  NotFoundError: If the trait has no tracker for the character's game version.
503
502
  AuthorizationError: If you are not the character's player or a storyteller.
504
- RequestValidationError: If a value is negative.
503
+ RequestValidationError: If a value is negative or a field is unknown.
505
504
  ValidationError: If a field does not fit the tracker type, a counter has no
506
505
  ``current``, or a value exceeds the tracker size.
507
506
  """
@@ -520,20 +519,16 @@ class CharacterTraitsService(BaseService):
520
519
  action: TrackerAction,
521
520
  *,
522
521
  amount: int = 1,
523
- damage_type: DamageType | None = None,
524
522
  ) -> Tracker:
525
523
  """Apply one in-play action to a trait tracker, such as spending Willpower.
526
524
 
527
- The server applies the game rules for the character's game version. Which actions
528
- and damage types fit each tracker is listed in ``characters.TrackerRules`` from
529
- ``options.get_options()``. A STAINS response reports overflow into Willpower in
530
- ``willpower_damage_applied``.
525
+ The actions each tracker accepts are listed in
526
+ ``characters.TrackerRules[game_version][tracker.type]`` from ``options.get_options()``.
531
527
 
532
528
  Args:
533
529
  character_trait_id: The ID of the character trait.
534
530
  action: The action to apply.
535
531
  amount: How many points to apply. Must be at least 1.
536
- damage_type: The damage type for ``damage`` and ``heal`` on damage tracks.
537
532
 
538
533
  Returns:
539
534
  The updated tracker.
@@ -542,12 +537,10 @@ class CharacterTraitsService(BaseService):
542
537
  NotFoundError: If the trait has no tracker for the character's game version.
543
538
  AuthorizationError: If you are not the character's player or a storyteller.
544
539
  RequestValidationError: If ``amount`` is less than 1.
545
- ValidationError: If the action or damage type does not fit the tracker, a
546
- damage type is missing or not allowed, or a spend exceeds the current value.
540
+ ValidationError: If the action does not fit the tracker or a spend exceeds the
541
+ current value.
547
542
  """
548
- body = self._validate_request(
549
- _TrackerAction, action=action, amount=amount, damage_type=damage_type
550
- )
543
+ body = self._validate_request(_TrackerAction, action=action, amount=amount)
551
544
  response = await self._post(
552
545
  self._format_endpoint(
553
546
  Endpoints.CHARACTER_TRAIT_TRACKER_ACTIONS, character_trait_id=character_trait_id
@@ -10,7 +10,6 @@ from vclient.constants import (
10
10
  CharacterInclude,
11
11
  CharacterStatus,
12
12
  CharacterType,
13
- DamageType,
14
13
  TrackerAction,
15
14
  )
16
15
  from vclient.endpoints import Endpoints
@@ -1033,15 +1032,14 @@ class CharactersService(BaseService):
1033
1032
  ) -> Health:
1034
1033
  """Replace a character's full health state, such as to correct a mistake.
1035
1034
 
1036
- Every field is sent, so omitted fields reset to 0. V4 uses ``bashing``,
1037
- ``lethal``, and ``aggravated``; V5 uses ``superficial`` and ``aggravated``.
1038
- ``extra_levels`` applies to both. Use ``apply_health_action`` for in-play changes.
1035
+ Every field is sent, so omitted fields reset to 0. Use ``apply_health_action`` for
1036
+ in-play changes.
1039
1037
 
1040
1038
  Args:
1041
1039
  character_id: The ID of the character.
1042
1040
  request: A HealthStateSet model, OR pass fields as keyword arguments.
1043
1041
  **kwargs: Fields for HealthStateSet if request is not provided.
1044
- Accepts: extra_levels, superficial, aggravated, bashing, lethal (int >= 0).
1042
+ Accepts: extra_levels, damage (int >= 0).
1045
1043
 
1046
1044
  Returns:
1047
1045
  The updated Health.
@@ -1049,9 +1047,8 @@ class CharactersService(BaseService):
1049
1047
  Raises:
1050
1048
  NotFoundError: If the character does not exist or has no health track.
1051
1049
  AuthorizationError: If you are not the character's player or a storyteller.
1052
- RequestValidationError: If a value is negative.
1053
- ValidationError: If a nonzero field is not used by the game version, or the
1054
- marks exceed the track size.
1050
+ RequestValidationError: If a value is negative or a field is unknown.
1051
+ ValidationError: If the damage exceeds the track size.
1055
1052
  """
1056
1053
  body = request if request is not None else self._validate_request(HealthStateSet, **kwargs)
1057
1054
  response = await self._put(
@@ -1066,19 +1063,16 @@ class CharactersService(BaseService):
1066
1063
  action: TrackerAction,
1067
1064
  *,
1068
1065
  amount: int = 1,
1069
- damage_type: DamageType | None = None,
1070
1066
  ) -> Health:
1071
1067
  """Apply one in-play action to a character's health, such as taking damage.
1072
1068
 
1073
- Health accepts ``damage``, ``heal``, and ``reset``. V4 damage types are
1074
- ``BASHING``, ``LETHAL``, and ``AGGRAVATED``; V5 damage types are ``SUPERFICIAL``
1075
- and ``AGGRAVATED``. The server applies overflow and upgrade rules.
1069
+ Health accepts ``damage``, ``heal``, and ``reset``. Damage past a full track and
1070
+ healing past 0 are dropped.
1076
1071
 
1077
1072
  Args:
1078
1073
  character_id: The ID of the character.
1079
1074
  action: The action to apply.
1080
1075
  amount: How many points to apply. Must be at least 1.
1081
- damage_type: The damage type for ``damage`` and ``heal``.
1082
1076
 
1083
1077
  Returns:
1084
1078
  The updated Health.
@@ -1087,11 +1081,9 @@ class CharactersService(BaseService):
1087
1081
  NotFoundError: If the character does not exist or has no health track.
1088
1082
  AuthorizationError: If you are not the character's player or a storyteller.
1089
1083
  RequestValidationError: If ``amount`` is less than 1.
1090
- ValidationError: If the action or damage type does not fit the game version.
1084
+ ValidationError: If the action does not apply to health.
1091
1085
  """
1092
- body = self._validate_request(
1093
- _TrackerAction, action=action, amount=amount, damage_type=damage_type
1094
- )
1086
+ body = self._validate_request(_TrackerAction, action=action, amount=amount)
1095
1087
  response = await self._post(
1096
1088
  self._format_endpoint(Endpoints.CHARACTER_HEALTH_ACTIONS, character_id=character_id),
1097
1089
  json=body.model_dump(exclude_none=True, mode="json"),
@@ -37,9 +37,9 @@ class OptionsService(BaseService):
37
37
  """Retrieve all options and enumerations for the api.
38
38
 
39
39
  Most values are lists of enum values. ``characters.TrackerRules`` is a nested map
40
- ``{game_version: {tracker_key: {"actions": [...], "damage_types": [...]}}}`` where
41
- ``tracker_key`` is a tracker type or ``HEALTH``. Use it to choose which tracker
42
- actions and damage types to offer instead of hardcoding them.
40
+ ``{game_version: {tracker_type: {"actions": [...]}}}``. Health is keyed by its
41
+ ``type``, ``DAMAGE``. Use it to choose which tracker actions to offer instead of
42
+ hardcoding them.
43
43
 
44
44
  Returns:
45
45
  A dictionary of options and enumerations for the api.
@@ -39,7 +39,6 @@ from vclient.testing._factories import (
39
39
  CompanyFactory,
40
40
  CompanyPermissionsFactory,
41
41
  CounterTrackerFactory,
42
- DamageTrackerFactory,
43
42
  DeveloperFactory,
44
43
  DeveloperWithApiKeyFactory,
45
44
  DicerollFactory,
@@ -100,7 +99,6 @@ __all__ = [
100
99
  "CompanyFactory",
101
100
  "CompanyPermissionsFactory",
102
101
  "CounterTrackerFactory",
103
- "DamageTrackerFactory",
104
102
  "DeveloperFactory",
105
103
  "DeveloperWithApiKeyFactory",
106
104
  "DicerollFactory",
@@ -1,6 +1,5 @@
1
1
  """Polyfactory model factories for all vclient response models."""
2
2
 
3
- import random
4
3
  from typing import Any
5
4
 
6
5
  from polyfactory import Use
@@ -31,7 +30,6 @@ from vclient.models import (
31
30
  Company,
32
31
  CompanyPermissions,
33
32
  CounterTracker,
34
- DamageTracker,
35
33
  Developer,
36
34
  DeveloperWithApiKey,
37
35
  Diceroll,
@@ -186,11 +184,9 @@ class CharacterTraitFactory(_GeneratedFieldsFactory[CharacterTrait]):
186
184
  __generated_fields__ = frozenset({"tracker"})
187
185
 
188
186
  @classmethod
189
- def tracker(cls) -> CounterTracker | DamageTracker | StainsTracker | None:
187
+ def tracker(cls) -> CounterTracker | StainsTracker | None:
190
188
  """Return a random tracker variant, or None for a trait without a tracker."""
191
- factory = cls.__random__.choice(
192
- [CounterTrackerFactory, DamageTrackerFactory, StainsTrackerFactory, None]
193
- )
189
+ factory = cls.__random__.choice([CounterTrackerFactory, StainsTrackerFactory, None])
194
190
  return factory.build() if factory is not None else None
195
191
 
196
192
 
@@ -370,24 +366,6 @@ class WerewolfTribeFactory(ModelFactory[WerewolfTribe]):
370
366
  __use_defaults__ = True
371
367
 
372
368
 
373
- def _damage_track_values(rng: random.Random, overrides: dict[str, Any]) -> dict[str, Any]:
374
- """Return damage track fields whose counts, boxes, and impairment agree with each other.
375
-
376
- Fields passed in ``overrides`` are kept and the rest are derived from them.
377
- """
378
- size: int = overrides.get("size", rng.randint(1, 10))
379
- aggravated: int = overrides.get("aggravated", rng.randint(0, size))
380
- superficial: int = overrides.get("superficial", rng.randint(0, max(size - aggravated, 0)))
381
- marks: list[str | None] = ["AGGRAVATED"] * aggravated + ["SUPERFICIAL"] * superficial
382
- return {
383
- "size": size,
384
- "aggravated": aggravated,
385
- "superficial": superficial,
386
- "boxes": overrides.get("boxes", (marks + [None] * size)[:size]),
387
- "is_impaired": overrides.get("is_impaired", aggravated + superficial >= size),
388
- }
389
-
390
-
391
369
  class CounterTrackerFactory(ModelFactory[CounterTracker]):
392
370
  __model__ = CounterTracker
393
371
  __use_defaults__ = True
@@ -400,25 +378,22 @@ class CounterTrackerFactory(ModelFactory[CounterTracker]):
400
378
  return super().build(factory_use_construct, **kwargs)
401
379
 
402
380
 
403
- class DamageTrackerFactory(ModelFactory[DamageTracker]):
404
- __model__ = DamageTracker
405
- __use_defaults__ = True
406
-
407
- @classmethod
408
- def build(cls, factory_use_construct: bool = False, **kwargs: Any) -> DamageTracker: # noqa: FBT001, FBT002
409
- """Build a damage track whose boxes match its superficial and aggravated counts."""
410
- kwargs = {**kwargs, **_damage_track_values(cls.__random__, kwargs)}
411
- return super().build(factory_use_construct, **kwargs)
412
-
413
-
414
381
  class HealthFactory(ModelFactory[Health]):
415
382
  __model__ = Health
416
383
  __use_defaults__ = True
417
384
 
418
385
  @classmethod
419
386
  def build(cls, factory_use_construct: bool = False, **kwargs: Any) -> Health: # noqa: FBT001, FBT002
420
- """Build a health track whose boxes match its superficial and aggravated counts."""
421
- kwargs = {**kwargs, **_damage_track_values(cls.__random__, kwargs)}
387
+ """Build a V4 or V5 health track whose damage fits it and whose V4 levels match it."""
388
+ size: int = kwargs.get("size", cls.__random__.randint(1, 10))
389
+ damage: int | None = kwargs.get("damage", cls.__random__.randint(0, size))
390
+ levels: list[HealthLevel] | None = kwargs.get("levels")
391
+ if "levels" not in kwargs and cls.__random__.choice((True, False)):
392
+ levels = [
393
+ HealthLevel(name=f"Level {i + 1}", marked=None if damage is None else i < damage)
394
+ for i in range(size)
395
+ ]
396
+ kwargs = {"size": size, "damage": damage, "levels": levels, **kwargs}
422
397
  return super().build(factory_use_construct, **kwargs)
423
398
 
424
399
 
@@ -426,6 +401,12 @@ class HealthLevelFactory(ModelFactory[HealthLevel]):
426
401
  __model__ = HealthLevel
427
402
  __use_defaults__ = True
428
403
 
404
+ @classmethod
405
+ def build(cls, factory_use_construct: bool = False, **kwargs: Any) -> HealthLevel: # noqa: FBT001, FBT002
406
+ """Build a health level in the current API shape, with ``marked`` set."""
407
+ kwargs = {"marked": cls.__random__.choice((True, False)), **kwargs}
408
+ return super().build(factory_use_construct, **kwargs)
409
+
429
410
 
430
411
  class StainsTrackerFactory(ModelFactory[StainsTracker]):
431
412
  __model__ = StainsTracker
@@ -470,7 +451,6 @@ __all__ = [
470
451
  "CompanyFactory",
471
452
  "CompanyPermissionsFactory",
472
453
  "CounterTrackerFactory",
473
- "DamageTrackerFactory",
474
454
  "DeveloperFactory",
475
455
  "DeveloperWithApiKeyFactory",
476
456
  "DicerollFactory",
@@ -33,7 +33,6 @@ from vclient.models import (
33
33
  Company,
34
34
  CompanyPermissions,
35
35
  CounterTracker,
36
- DamageTracker,
37
36
  Developer,
38
37
  DeveloperWithApiKey,
39
38
  Diceroll,
@@ -87,7 +86,6 @@ from vclient.testing._factories import (
87
86
  CompanyFactory,
88
87
  CompanyPermissionsFactory,
89
88
  CounterTrackerFactory,
90
- DamageTrackerFactory,
91
89
  DeveloperFactory,
92
90
  DeveloperWithApiKeyFactory,
93
91
  DicerollFactory,
@@ -121,7 +119,6 @@ from vclient.testing._routes import BYTES, LIST, NO_CONTENT, PAGINATED, RAW_JSON
121
119
 
122
120
  _FACTORY_MAP: dict[type, type[ModelFactory]] = {
123
121
  CounterTracker: CounterTrackerFactory,
124
- DamageTracker: DamageTrackerFactory,
125
122
  Health: HealthFactory,
126
123
  HealthLevel: HealthLevelFactory,
127
124
  StainsTracker: StainsTrackerFactory,
@@ -23,7 +23,7 @@ from vclient.models import (
23
23
  CharacterTraitValueOptionsResponse,
24
24
  Company,
25
25
  CompanyPermissions,
26
- DamageTracker,
26
+ CounterTracker,
27
27
  Developer,
28
28
  DeveloperWithApiKey,
29
29
  Diceroll,
@@ -351,15 +351,15 @@ class Routes:
351
351
  CHARACTER_TRAITS_SPECIALTY_DELETE = RouteSpec(
352
352
  "DELETE", Endpoints.CHARACTER_TRAIT_SPECIALTY, NO_CONTENT, None
353
353
  )
354
- # Tracker routes return any tracker variant; the default response is a DamageTracker.
354
+ # Tracker routes return any tracker variant; the default response is a CounterTracker.
355
355
  CHARACTER_TRAITS_TRACKER_GET = RouteSpec(
356
- "GET", Endpoints.CHARACTER_TRAIT_TRACKER, SINGLE, DamageTracker
356
+ "GET", Endpoints.CHARACTER_TRAIT_TRACKER, SINGLE, CounterTracker
357
357
  )
358
358
  CHARACTER_TRAITS_TRACKER_SET = RouteSpec(
359
- "PUT", Endpoints.CHARACTER_TRAIT_TRACKER, SINGLE, DamageTracker
359
+ "PUT", Endpoints.CHARACTER_TRAIT_TRACKER, SINGLE, CounterTracker
360
360
  )
361
361
  CHARACTER_TRAITS_TRACKER_ACTION = RouteSpec(
362
- "POST", Endpoints.CHARACTER_TRAIT_TRACKER_ACTIONS, SINGLE, DamageTracker
362
+ "POST", Endpoints.CHARACTER_TRAIT_TRACKER_ACTIONS, SINGLE, CounterTracker
363
363
  )
364
364
 
365
365
  # Blueprint sections
@@ -70,7 +70,6 @@ CONSTANT_MAP: dict[str, ConstantMapping] = {
70
70
  "CharacterInventoryType": ConstantMapping("characters", "InventoryItemType"),
71
71
  "CharacterStatus": ConstantMapping("characters", "CharacterStatus"),
72
72
  "CharacterType": ConstantMapping("characters", "CharacterType"),
73
- "DamageType": ConstantMapping("characters", "DamageType"),
74
73
  "DiceSize": ConstantMapping("gameplay", "DiceSize"),
75
74
  "FreeTraitChangesPermission": ConstantMapping("companies", "PermissionsFreeTraitChanges"),
76
75
  "GameVersion": ConstantMapping("characters", "GameVersion"),