270 lines
45 KiB
Markdown
270 lines
45 KiB
Markdown
|
|
Fiche STE-ORG4 — Niveau N3 — Modèle prévu (modèle de l'agent lp-cart) | utilisé claude-sonnet-5-5 — Agent lp-cart — Skills lp-mcp (invoqué : § 1, 3, 4), sk-protocol (préchargés avec l'agent : ue-cpp-build, lp-commandlets, lp-paths)
|
|||
|
|
# STE-ORG4-SPEC : fin de scène par `Endsex` — bonus d'orgasme absent et lecture de `PersonCumming` à None (2026-10-14)
|
|||
|
|
|
|||
|
|
Hors gabarit : les sections suivent le gabarit SPEC de `D:\Game\LifePlay-Sandbox\Tools\claude\skills\lp-doc\gabarits.md` (§ 1 à 7, dans l'ordre) ; correspondance avec la rubrique 7 de la fiche : objectif = § 1 ; fichiers et ordre, préalables, correctif au geste près, garde, comportement = § 2 (2.0 à 2.5) ; repli = § 3 ; risques et Q# = § 4 ; interdits = § 5 ; critères V5 / V6 = § 7. Lecture seule stricte (Read, Grep, Glob ; Bash pour `git rev-parse`, `md5sum`, `git status`, `git log`, `ls`, `grep -a -c` sur un binaire) ; aucun éditeur, MCP, commandlet, build ni jeu ; un seul fichier écrit : ce livrable.
|
|||
|
|
|
|||
|
|
## Annonce en tête (fiche, rubrique 3)
|
|||
|
|
- **Person n'est pas touché** par le correctif (aucune écriture, aucun `save_assets` de Person) : il appelle l'événement existant `GiveOrgasmReward` de Person (lecture de son nom seulement). Pas d'annonce à Big Boss pour Person.
|
|||
|
|
- **GI est touché** (`Content\BPs\GI.uasset`, graphe `EventGraph` seul) : le fichier contient déjà deux changements non commités d'autres lots (G16 de STE-H3g, B7-a de STG ; § 2.0). **SexAction (`UI/SexAction.uasset`) n'est pas touché** mais sa lecture (P0) est **bloquante** pour la partie O4b (§ 2.0).
|
|||
|
|
- **Statut : exécutable par MCP en deux parties** : **O4a** (garde `PersonCumming`, sans changement de comportement) est complète et indépendante ; **O4b** (bonus à `Endsex`, changement de comportement voulu) est complète **sous la condition P0** (lecture de `SexAction`) et **sous la réponse Q-ORG4-1** de l'utilisateur.
|
|||
|
|
|
|||
|
|
Abréviations (chemins absolus) :
|
|||
|
|
- **E** = `D:\Game\LifePlay-master 5.8\Docs\Migration\etat\` ; **GI-P2** = E`ST\STE\dumps\GI__EventGraph_P2.txt` (2026-10-13 16:36, GI `c4817b84`, 6 249 nœuds) ; **P-STG** = E`ST\STG\dumps\Person__EventGraph.txt` (2026-10-13 14:08) ; **PC-STE** = E`ST\STE\dumps\PC__EventGraph.txt` (2026-10-10 11:33) ; **PASA** = E`ST\STA\dumps\GI__PlayAppropriateSexAnimation.txt` (préfixe `LogLPDump: Warning:` sur chaque ligne) ; **L6f-G** = E`portage55\L6f\L6f_dump_GI.txt` (5.5, 2026-09-30).
|
|||
|
|
- **HJ** = E`ST\STE\STE-H3e-J\LifePlay.log` (journal H3e, ligne de commande `-ScriptStackOnWarnings -LPHitchLog`) ; **J6** = `D:\Game\LifePlay_Build_5.8_STE-J6_Development\Windows\LifePlay\Saved\Logs\LifePlay.log`.
|
|||
|
|
- **AUD** = E`ST\STE\STE-ORG-AUDIT.md` ; **H3fD** = `STE-H3f-DIAG.md` ; **H3gS** / **H3gI** / **H3gV** = `STE-H3g-SPEC.md` / `-IMPL.md` / `-VAL.md` ; **H3dI** = `STE-H3d-IMPL.md` (tous dans E`ST\STE\`) ; **B7aI** = E`ST\STG\STG-B7a-IMPL.md` ; **UE** = `D:\Game\Launcher\Engine\UE_5.8\Engine\Source\`.
|
|||
|
|
|
|||
|
|
## État relevé à l'entrée de cette SPEC (C9a de la fiche ; Bash, lecture)
|
|||
|
|
| Commande | Sortie |
|
|||
|
|
|---|---|
|
|||
|
|
| `git rev-parse --short HEAD` | `0745917` |
|
|||
|
|
| `md5sum Content/BPs/GI.uasset` | `e64b5b37c9ef0db7735de0d6e3bd7c1c` |
|
|||
|
|
| `md5sum Content/BPs/Person.uasset` | `8668a47c627f7a5254910cf0ac33b12a` |
|
|||
|
|
| `md5sum Content/BPs/Room.uasset` | `18565365b1195bf2416a1048bf9051b6` |
|
|||
|
|
| `md5sum Content/UI/SexAction.uasset` | `a8705f7fbe1fde1daba0464bfc9ff9b5` |
|
|||
|
|
| `md5sum Content/BPs/PC.uasset` | `a19510e613f31905437bab48f38c6154` |
|
|||
|
|
| `git status --short -- Content/BPs/GI.uasset Content/BPs/Person.uasset Content/BPs/Room.uasset Content/UI/SexAction.uasset Content/BPs/PC.uasset` | ` M` pour GI, Person, Room ; SexAction et PC non listés (= HEAD) |
|
|||
|
|
|
|||
|
|
Historique de GI (établi) : `c4817b84` (dump GI-P2, EventGraph 6 249 nœuds) → G16 de STE-H3g → `0E6AEDCC` (EventGraph **6 253** nœuds, H3gV:13, 29 ; G16 ne modifie que 7 nœuds communs, tous dans `UpdateDefaultHair`, H3gV:32) → B7-a de STG, **fonction `Show` seule** (B7aI:9, 104-110) → `e64b5b37` (valeur actuelle). **Nœuds du chemin `Cum` qui pourraient avoir changé de nom : aucun** (établi : H3gV:32 liste les seuls nœuds modifiés par G16, aucun n'est sur le chemin ; B7a n'a pas touché l'EventGraph) ; le dump GI-P2 reste donc valable pour tout ce qui suit, **sauf** les noms des nœuds à créer (attribués par l'éditeur : à relever). Exiger tout de même P1 / P2 à l'IMPL (§ 2.0).
|
|||
|
|
Dates (établi, `ls -l --time-style=long-iso`) : `Person.uasset` modifié le 2026-10-13 à 17:42, **après** le dump P-STG (14:08) : les nœuds de Person cités ci-dessous (chaîne `Cum` / `GiveOrgasmReward`) viennent d'un dump antérieur à la dernière sauvegarde de Person (STG G-B1a, K8-a : `B239E103…` → `8668A47C…`) ; ces écritures visent d'autres fonctions (estimé) ; P7 le re-vérifie en lecture. `PC-STE` (10-10) précède le commit CAM-B1 qui a touché PC (`git log`, a08c134) : les lignes de PC citées sont descriptives, elles ne conditionnent pas le correctif.
|
|||
|
|
|
|||
|
|
## 1. Objectif mesurable
|
|||
|
|
|
|||
|
|
### 1.1 Cause exacte (chemins `Finish`, auto-100, `Endsex` : où ils divergent)
|
|||
|
|
`Person::Cum` est le **seul écrivain** de `PersonCumming` : `VariableSet_211` (`PersonCumming := self`, `self` du `Set` = GI) P-STG:17592-17599, suite de l'événement `Cum` de Person (P-STG:15920-15922). Dans l'EventGraph de GI : **0 écriture, 1 lecteur** (Grep `PersonCumming` sur GI-P2 → `VariableGet_720` et ses deux lectures de membres, GI-P2:28040-28062). Autres graphes de GI : non lus (§ 4, L-PC).
|
|||
|
|
|
|||
|
|
| Chemin | Séquence (fichier:ligne) | `Person::Cum` appelé ? | `PersonCumming` |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| **Auto 100** | `UpdateOeChange` → `Sex_Orgasm == 100.0` → `Cum()` (P-STG:16030-16043) | oui | écrit (P-STG:17592) |
|
|||
|
|
| **Finish** (« Cum on … ») | PC propose les animations `Finish` si `Sex_Orgasm >= 90` de `SexPersons[0]` (PC-STE:6075-6092, 6123-6142) → PASA : `Array_Contains(Tags,'Finish')` → `Person_C::Cum()` sur `Persons[0]` (PASA:348-361, 85-90) | oui | écrit |
|
|||
|
|
| **Endsex** | PC crée le widget d'action avec `Animation = 'Endsex'` et le libellé `SelectString('Finish showering','Finish having sex')` (PC-STE:2476-2485, 2668-2673) → clic : `SexAction` imprime `Endsex (Animation String)` (HJ:9242) → pile `SexAction:BndEvt…OnButtonClicked → ExecuteUbergraph_SexAction → GI_C:cum → ExecuteUbergraph_GI → AfterCumSpeed` (HJ:9246-9252) | **non** | **jamais écrit** sur ce chemin |
|
|||
|
|
| **Exhausted** | `Exhausted` → `StopUpdateOeForSexPersons` → `SetText` → `GI.Cum(NoPregCheck true, NoEnd false, NoShake true)` (P-STG:15993-16016) | non (aucun `VariableSet_211` dans cette chaîne) | non écrit (même défaut) |
|
|||
|
|
|
|||
|
|
**Cause** (établi pour les nœuds, estimé pour la valeur des broches de l'appel de `SexAction`) : `GI::Cum` (événement `K2Node_CustomEvent_4245`, GI-P2:10803-10809) n'est pas l'événement d'orgasme : c'est le **traitement d'après-orgasme / de fin de scène** que `Person::Cum` appelle lui-même (`GI.Cum(NoEnd = true)`, P-STG:15936-15973) ; le bouton `Endsex` l'appelle **directement**, sans passer par `Person::Cum`. Ni `GiveOrgasmReward` ni l'écriture de `PersonCumming` ne sont donc atteintes. Les 22 nœuds atteints depuis `GI::Cum` (AUD § 2, parcours d'exécution) ne contiennent ni `Person::Cum` ni `GiveOrgasmReward` ; relu aujourd'hui, seul appelant de `Person_C::Cum` / `GiveOrgasmReward` dans GI-P2 : aucun (Grep `appel [A-Za-z_?]+::(Cum|EndSex|AfterCumSpeed|GiveOrgasmReward)\(\)` → GI-P2:10840 `?::Cum()` (ancien modèle), 10905 `AfterCumSpeed`, 14564 `EndSex` seulement). Même pile en 4.27 (H3fD:74) : **ce n'est pas une régression de portage**, c'est la conception d'origine : `Endsex` n'est pas un orgasme.
|
|||
|
|
|
|||
|
|
Valeur de `PersonCumming` à `Endsex` (estimé) : `None` si personne n'a joui depuis le début de la partie (HJ:9243, 9262 : 2 avertissements pour 1 clic) ; **périmée mais valide** (dernier jouisseur) sinon, car aucune écriture de remise à zéro dans l'EventGraph de GI (explique J6:2849 : un `Endsex`, aucune ligne `PersonCumming` — le Grep de J6 sur `Endsex|PersonCumming|Accessed None` ne rend aucune ligne `PersonCumming`).
|
|||
|
|
|
|||
|
|
Chemin `Endsex` dans GI, avec l'hypothèse `ForceEnd = true` (**estimé fort**, § 4 R-ORG4-1) : `CustomEvent_4245` → `IfThenElse_172` (`CondomBroke`, GI-P2:27020-27024 ; `else` → `VariableSet_329`, 27003-27008) → `IfThenElse_98` (`SexOn`, 22660-22667 ; `else` vide) → **`IfThenElse_875`** (`Condition` = `ForceEnd`, `then` → `CallFunction_11423`, `else` → `MacroInstance_18`, 14554-14558) → `CallFunction_11423` = appel de l'événement `AfterCumSpeed` (10905-10908) → `CallFunction_76765` `StopDirtyTalkAndDescription` → `32952` `DirtyTalkEnd` → `32953` `DescriptionEnd` (10810-10821) → `IfThenElse_188` (`BooleanOR(ForceEnd, NoPregCheck, NoShake)`, 27663-27667, 27914-27919 ; vrai → saute `CheckConceived`) → `CallFunction_38905` `PC::StopUpdateSpeed` (10825-10828) → `IfThenElse_876` (`ForceEnd`, `then` → `CallFunction_4939` `EndSex()`, 14559-14567). `AfterCumSpeed` (événement `CustomEvent_702`, 10896-10898) : `VariableSet_9760` `Rate` ← `SelectFloat(A = 0.0, B = 0.25, bPickA = StartsWith(Race(PersonCumming),'Dog') AND IsMale(PersonCumming))` (10899-10904 ; 28034-28062) puis `CallFunction_960` `UpdateOeDisplayOnly(Feedback = false)` (27658-27662) puis la boucle `MacroInstance_806` sur `SexPersons` (7094-7100).
|
|||
|
|
Preuves que `Endsex` suit cette branche : (a) aucun appelant dumpé (GI 5.8 et 5.5, Person 5.8 et 5.5, PC, SexInterface, Scène 5.5, Room) ne passe `ForceEnd = true` : GI-P2:10844 (`false`) ; L6f-G:58598 (`false`) ; Person 5.5 : `false` ×3 (E`portage55\L6f\L6f_dump_Person.txt:37160, 37168, 37202`) ; PC, SexInterface, Scène, Room : 0 occurrence ; (b) la scène se termine **dans la même image** que le clic (HJ:9281-9296, image 883 : remise en place des personnes et des meubles), alors que le chemin à minuterie (`NoEnd` faux) retarde `EndSex` de 10 s (GI-P2:10829-10839) ; (c) `SexAction.uasset` contient la chaîne `Endsex` (2 lignes), `ForceEnd` (1), `NoPregCheck` (1), `PlayAppropriateSexAnimation` (1) (`grep -a -c`) : le widget compare l'animation à `Endsex`, appelle `Cum` et `PlayAppropriateSexAnimation`. **Ce qui n'est pas lu : les valeurs des broches de l'appel `GI.Cum` dans `SexAction`** (aucun dump de `SexAction` n'existe : Glob `E**\*SexAction*` → aucun fichier). D'où P0.
|
|||
|
|
|
|||
|
|
### 1.2 Objectifs mesurables (deux parties)
|
|||
|
|
- **O4a — garde `PersonCumming`** (sans changement de comportement) : les 2 lignes `LogScript: Warning: Accessed None trying to read (real) property PersonCumming in /Game/BPs/GI.GI_C` par clic `Endsex` (HJ:9243, 9262) → **0**. `GI:EventGraph` : N0 → **N0 + 3** nœuds (N0 attendu 6 253, H3gV:29).
|
|||
|
|
- **O4b — bonus à `Endsex`** (changement de comportement voulu, Q-ORG4-1) : à `Endsex`, `SexPersons[0]` reçoit `GiveOrgasmReward` **si et seulement si sa jauge `Sex_Orgasm` ≥ 90** (même éligibilité que l'animation `Finish`, PC-STE:6128-6142) ; personne d'autre, rien en dessous de 90, pas d'effet d'orgasme (pas de `Person::Cum`). `GI:EventGraph` : + **8** nœuds (+ **1** marqueur de trace si Q-ORG4-3 = oui).
|
|||
|
|
- Total attendu : `GI:EventGraph` **N0 + 11** (6 264) sans marqueur, **N0 + 12** (6 265) avec ; 2 coupures ; 22 liens (23) ; 2 valeurs posées (4) ; MD5 de Person et de SexAction inchangés.
|
|||
|
|
|
|||
|
|
## 2. Fichiers touchés, ordre
|
|||
|
|
Un seul fichier : `Content\BPs\GI.uasset`, graphe `EventGraph` (événements `AfterCumSpeed` et `Cum`). Ni Person, ni SexAction, ni PC, ni le C++, ni les scènes, ni les modules. **Ordre** : P0 à P7 → O4a → O4b → `compile_blueprint` → `save_assets` unique → fermeture de l'éditeur. O4a et O4b dans **une seule session MCP, un seul instantané, un seul `save_assets`** (comme H3g § 2). Si P0 contredit l'hypothèse `ForceEnd`, ou si Q-ORG4-1 = (a), **exécuter O4a seul** (§ 3).
|
|||
|
|
|
|||
|
|
### 2.0 Préalables
|
|||
|
|
- **P0 (bloquant pour O4b ; lecture, UE-GO de l'orchestrateur)** — dump du gestionnaire de clic de `SexAction` (lecture L1 de AUD § 5, jamais faite), éditeur fermé (`.\Tools\UeState.ps1 -Kind Editeur` = 0) :
|
|||
|
|
`.\Tools\RunCommandlet.ps1 -Lot STE-ORG4 -Commandlet LPDumpFunction -Args '-BP=SexAction -Fn=EventGraph -Pins -Exec' -EtatDir "D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE"`
|
|||
|
|
(le résolveur de `-BP` a trouvé `Action` sous `UI/` pour `Action__EventGraph_P2.txt` ; pour `SexAction` : non essayé). **Attendu** : sur le chemin de la comparaison avec `'Endsex'`, un nœud d'appel `GI_C::Cum` avec `ForceEnd = 'true'`, et aucun appel direct de `GI_C::EndSex`. **Écart** (ForceEnd faux, ou `EndSex` appelé par le widget, ou plusieurs appels) : **arrêt, rapport** ; O4b n'aurait aucun effet (V5 passerait, V6-S1 échouerait) ; ancre de repli à spécifier d'après ce dump.
|
|||
|
|
- **P1 (dump à l'entrée)** : MD5 de GI à l'entrée. Si `e64b5b37…` : le dump GI-P2 + H3gV:32 suffisent pour les liens du chemin `Cum`, mais **refaire** le dump pour fixer N0 et relever les noms : `.\Tools\RunCommandlet.ps1 -Lot STE-ORG4 -Commandlet LPDumpFunction -Args '-BP=GI -Fn=EventGraph -Pins -Exec' -EtatDir "D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE"` (éditeur fermé ; 61 s en H3g, H3gV:29) → en-tête `=== GI :: EventGraph (6253 noeuds) ===` attendu. Autre MD5 ou autre N0 : arrêt, rapport.
|
|||
|
|
- **P2** : MD5 de GI relevé juste avant l'IMPL (attendu `e64b5b37…`) = valeur de repli.
|
|||
|
|
- **P3** : gel annoncé à **toutes** les sessions (`lp-mcp` § 1 règle 7) ; `.\Tools\Snapshot.ps1 -Lot STE-ORG4` (`Content\BPs\GI.uasset` ; l'instantané contient donc G16 et B7-a, non commités) ; éditeur headless (`lp-mcp` § 2) ; `AssetTools.load_asset` `/Game/BPs/GI`.
|
|||
|
|
- **P4** (`get_node_infos {nodes:[{refPath:"/Game/BPs/GI.GI:EventGraph.K2Node_<Nom>"}]}`, deux appels de dix nœuds au plus ; liens = GI-P2 ; **relever** les indices de broches ; tout écart : arrêt) :
|
|||
|
|
1. `CustomEvent_4245`, `IfThenElse_172`, `IfThenElse_98`, `IfThenElse_875`, `CallFunction_11423`, `CustomEvent_702`, `VariableSet_9760`, `CallFunction_960`, `VariableGet_720`, `VariableGet_3498` ;
|
|||
|
|
2. `GetArrayItem_1037`, `CallFunction_6681`, `VariableGet_721`, `VariableGet_722`, `IfThenElse_188`, `IfThenElse_189`, `CallFunction_38905`, `CallFunction_4939`.
|
|||
|
|
Liens attendus : `IfThenElse_875.then` → `CallFunction_11423.execute` seul ; `CallFunction_11423.execute` ← `IfThenElse_875.then`, `CallFunction_32955.then`, `IfThenElse_189.then` (GI-P2:10906) ; `CustomEvent_702.then` → `VariableSet_9760.execute` (10898) ; `VariableSet_9760.then` → `CallFunction_960.execute` (10901) ; `VariableGet_720.PersonCumming` → `VariableGet_721.self`, `VariableGet_722.self` (28041) ; `VariableGet_3498.SexPersons` → `GetArrayItem_1037.Array` ; `GetArrayItem_1037.Output` → `CallFunction_6681.self`, `Dimension 1` = `0` (10879-10888).
|
|||
|
|
- **P5** : avant chaque `create_node`, `find_node_types {graph, type_id_filter, context_pins:[]}` ; le `type_id` attendu doit figurer dans la réponse ; après création, `get_node_infos` du nœud (indices). **Pas de type_id improvisé.**
|
|||
|
|
- **P6** : P0 lu et conforme (O4b) ; Q-ORG4-1 répondue (O4b) ; Q-ORG4-3 répondue (marqueur).
|
|||
|
|
- **P7** (lecture, sans écriture) : `find_node_types` avec le filtre `GiveOrgasmReward` doit rendre `Classe|Person|GiveOrgasmReward` (Person MD5 `8668a47c…` à l'entrée ; sinon arrêt) ; relever la broche `self`. Aucun enregistrement de Person.
|
|||
|
|
|
|||
|
|
### 2.1 Conventions (reprises de H3gS § 2.1, H3dI § 1.2, `lp-mcp` § 3-4)
|
|||
|
|
- `type_id` déjà relus en 5.8 : Branche `Utilitaires|ContrôleDeFlux|Branche` (execute 0, Condition 1 = `true` par défaut ; then 0, else 1 ; H3dI:69) ; `Utilitaires|Tableau|IsValidIndex` (`TargetArray` 0, `IndexToTest` 1 = `0` par défaut, `ReturnValue` 0 ; H3dI:68, 187-188) ; `Utilitaires|IsValid` (pur, `Object` 0, `ReturnValue` 0 ; H3gI:45) ; appel d'un événement de Person depuis GI `Classe|Person|<Nom>` (exemple créé : `Classe|Person|MovetoPersonStand`, B7aI:37-38 ; `Classe|Person|RevertStripAll`, STE-H10-GI1-IMPL.md:48) ; lecteur d'une variable de Person depuis GI `Classe|Person|Obtenir<Var>` (exemple : `Classe|Person|ObtenirValid`, `self` entrée 0, STE-H10-GI1-IMPL.md:47) — le tiret bas disparaît du nom (`Vol_BGA` → `ObtenirVolBGA`, `STF-T3-IMPL.md:59`) ; setter d'une variable de GI `Variables|<Catégorie>|Définir<Var>` (catégorie `Pardéfaut`, H3dI:70 ; catégorie `Sex` pour `SexOn`, B7aI:34) ; opérateur promotable `Utilitaires|Opérateurs|Inférieurà(<)` (créé en B7a : B7aI:32 ; typé en reliant `A` d'abord, puis `B` posé par `set_pin_value`, B7aI:44) ; `Math|Flottant|float<float` n'est **pas** créable (B7aI:31).
|
|||
|
|
- **Pas de `Person::Cum` appelé depuis `GI::Cum`** (décision de conception, § 2.3 et R-ORG4-5). Cascades de Branche ; ni AND, ni OR, ni Select purs. `delete_node` interdit. Positions libres.
|
|||
|
|
- Compilation et enregistrement : `compile_blueprint {blueprint:{refPath:"/Game/BPs/GI.GI"}, warnings_as_errors:true}` → `null`, journal de l'éditeur lu (aucune ligne Error / Warning liée à GI) ; **puis** `save_assets {asset_paths:["/Game/BPs/GI"]}` ; `hyper_blueprint_debug_inspect` absent du serveur (mémoire du projet ; H3dI:156) : repli = compilation stricte + journal ; fermeture de l'éditeur, `.\Tools\UeState.ps1` = 0, MD5 relevé.
|
|||
|
|
|
|||
|
|
### 2.2 Garde `PersonCumming` — O4a (graphe `/Game/BPs/GI.GI:EventGraph`, événement `AfterCumSpeed`)
|
|||
|
|
|
|||
|
|
**Avant** (GI-P2:10896-10904, 28034-28062) : `CustomEvent_702.then` → `VariableSet_9760.execute` ; `VariableSet_9760.Rate` ← `CallFunction_1002.ReturnValue` (pur) ← `CallFunction_1005` (`StartsWith`) et `VariableGet_722.IsMale`, tous deux avec `self` ← `VariableGet_720.PersonCumming`. Deux lectures de membres sur `PersonCumming` = deux avertissements par clic si `None`. « Vide » (`None`) est un **état normal** de ce chemin (aucun jouisseur) : l'`IsValid` est donc justifié (`lp-mcp` § 1 règle 4).
|
|||
|
|
|
|||
|
|
**Nœuds créés** (3) :
|
|||
|
|
| ID | Nœud | type_id (P5) | Broches (P4 / `get_node_infos`) |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| O4a-V | IsValid (pur) | `Utilitaires|IsValid` | `Object` 0, `ReturnValue` 0 |
|
|||
|
|
| O4a-B | Branche | `Utilitaires|ContrôleDeFlux|Branche` | execute 0, Condition 1 ; then 0, else 1 |
|
|||
|
|
| O4a-S | Définir `Rate` | `Variables|<catégorie>|DéfinirRate` — catégorie inconnue : `find_node_types` filtre `Rate` ; le nœud créé doit porter `|SetRate` comme `VariableSet_9760` | execute 0, `Rate` 1 ; then 0 |
|
|||
|
|
|
|||
|
|
**Coupure** (1) : `break_pins` `CustomEvent_702.then` (sortie 0) / `VariableSet_9760.execute` (entrée 0).
|
|||
|
|
**Liens** (6), un appel par message :
|
|||
|
|
1. `VariableGet_720.PersonCumming` → `O4a-V.Object` (0) (les liens vers `VariableGet_721.self` et `VariableGet_722.self` restent) ;
|
|||
|
|
2. `CustomEvent_702.then` (0) → `O4a-B.execute` (0) ;
|
|||
|
|
3. `O4a-V.ReturnValue` (0) → `O4a-B.Condition` (1) ;
|
|||
|
|
4. `O4a-B.then` (0) → `VariableSet_9760.execute` (0) ;
|
|||
|
|
5. `O4a-B.else` (1) → `O4a-S.execute` (0) ;
|
|||
|
|
6. `O4a-S.then` (0) → `CallFunction_960.execute` (0) (celui-ci garde `VariableSet_9760.then`).
|
|||
|
|
**Valeur** (1) : `set_pin_value` `O4a-S.Rate` (entrée 1) = `0.25` (relire la valeur par défaut avant et après).
|
|||
|
|
**Relecture** : `CustomEvent_702.then` → `O4a-B.execute` seul ; `VariableSet_9760.execute` ← `O4a-B.then` seul ; `CallFunction_960.execute` ← `VariableSet_9760.then`, `O4a-S.then` ; `VariableGet_720.PersonCumming` → 3 cibles ; `O4a-B.Condition` relié (sinon `true` par défaut = garde inopérante).
|
|||
|
|
**Comptes O4a** : 3 nœuds ; 1 coupure ; 6 liens ; 1 valeur.
|
|||
|
|
|
|||
|
|
Pourquoi `Rate = 0.25` explicite sur `else` (et non un saut direct vers `CallFunction_960`) : avec `PersonCumming = None`, les deux lectures rendent la valeur par défaut (`Race` vide → `StartsWith('Dog')` faux ; `IsMale` faux), `bPickA` = faux et `SelectFloat` rend `B` = 0.25 (« If bPickA is true, A is returned, otherwise B is », `UE`Runtime\Engine\Classes\Kismet\KismetMathLibrary.h:3850-3852 ; sémantique d'une lecture `Accessed None` : H3fD:86-88, estimé). Le `else` pose donc exactement la valeur d'aujourd'hui, y compris pour le chemin `Exhausted` (qui laisse 10 s avant `EndSex` et pour lequel `Rate` sert encore, estimé).
|
|||
|
|
|
|||
|
|
### 2.3 Bonus à `Endsex` et ses gardes — O4b (même graphe, événement `Cum`, branche `ForceEnd`)
|
|||
|
|
|
|||
|
|
**Principe** (Q-ORG4-1 option b, recommandée) : sur la branche `ForceEnd` vrai de `GI::Cum`, **avant** l'appel de `AfterCumSpeed`, donner `GiveOrgasmReward` à `SexPersons[0]` si `Sex_Orgasm ≥ 90`. Le bonus est lu **avant** `EndSex` (qui vide la scène) : `SexPersons`, `PlayerCharacter` et `SexOn` sont encore valides. Le bonus ne comprend que ce que fait `GiveOrgasmReward` (P-STG:16059-16106, 19071-19101 d'après AUD § 1) : `OrgasmIrBoost`, puis `mood` +20 (joueur) ou `attractiontoplayer` +3 / +6 (PNJ avec le joueur dans la scène), rien sinon.
|
|||
|
|
Pourquoi **bonus seul** et non `Person::Cum` : (1) `Person::Cum` rappelle `GI.Cum` (P-STG:15958-15973) ; appelé depuis `GI::Cum`, il ré-entrerait dans le même événement dont les paramètres (`ForceEnd`, `NoEnd`…) sont, en Blueprint, des variables de la trame de l'ubergraph partagée ; l'appel interne écraserait `ForceEnd` à `false` et la fin de scène (`IfThenElse_188`, `IfThenElse_876`, `CallFunction_4939`) lirait la valeur écrasée (**estimé fort**, non lu dans le moteur : raison suffisante pour s'en abstenir) ; (2) fumée, texte, secousse et son d'orgasme seraient joués à l'image même où la scène est défaite ; (3) l'événement `GiveOrgasmReward` n'appelle aucun nœud de GI (AUD § 1 : 6 nœuds) donc aucune ré-entrée.
|
|||
|
|
|
|||
|
|
**Nœuds créés** (8, + 1 si Q-ORG4-3 = oui) :
|
|||
|
|
| ID | Nœud | type_id (P5) | Broches |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| O4b-I | IsValidIndex | `Utilitaires|Tableau|IsValidIndex` | `TargetArray` 0, `IndexToTest` 1 = `0` (défaut, ne pas poser), `ReturnValue` 0 |
|
|||
|
|
| O4b-B1 | Branche | `Utilitaires|ContrôleDeFlux|Branche` | execute 0, Condition 1 ; then 0, else 1 |
|
|||
|
|
| O4b-V | IsValid (pur) | `Utilitaires|IsValid` | `Object` 0, `ReturnValue` 0 |
|
|||
|
|
| O4b-B2 | Branche | idem | idem |
|
|||
|
|
| O4b-G | Lecteur de `Sex_Orgasm` (Person) | `Classe|Person|Obtenir…` : filtre `Orgasm` ; attendu `Classe|Person|ObtenirSexOrgasm` (modèle `ObtenirValid`) ; **le type de la variable est `double`** (`EqualEqual_DoubleDouble` P-STG:16030-16033 ; `GreaterEqual_DoubleDouble` PC-STE:6128-6132) | `self` 0 ; sortie `Sex_Orgasm` 0 |
|
|||
|
|
| O4b-C | Comparateur `<` | `Utilitaires|Opérateurs|Inférieurà(<)` (promotable, créé en B7a) | `A` 0, `B` 1 ; `ReturnValue` 0 |
|
|||
|
|
| O4b-B3 | Branche | idem | idem |
|
|||
|
|
| O4b-M (option) | PrintString (marqueur de trace) | filtre `PrintString` | `InString`, `bPrintToScreen`, `bPrintToLog` (défaut vrai) ; execute 0, then 0 |
|
|||
|
|
| O4b-R | Appel de `Person_C::GiveOrgasmReward` | `Classe|Person|GiveOrgasmReward` (P7) | execute 0, `self` 1 ; then 0 |
|
|||
|
|
Repli de type pour O4b-C si la création échoue : `Utilitaires|Opérateurs|Supérieuràouégalà(>=)` (listé, non créé : B7aI:24) avec Branche inversée ; sinon arrêt, rapport.
|
|||
|
|
|
|||
|
|
**Coupure** (1) : `break_pins` `IfThenElse_875.then` (sortie 0) / `CallFunction_11423.execute` (entrée 0).
|
|||
|
|
**Liens** (16 ; 17 avec le marqueur), un appel par message, dans cet ordre (relier `O4b-G` → `O4b-C.A` **avant** de poser `B`) :
|
|||
|
|
1. `IfThenElse_875.then` (0) → `O4b-B1.execute` (0) ;
|
|||
|
|
2. `VariableGet_3498.SexPersons` → `O4b-I.TargetArray` (0) (le lien vers `GetArrayItem_1037.Array` reste) ;
|
|||
|
|
3. `O4b-I.ReturnValue` (0) → `O4b-B1.Condition` (1) ;
|
|||
|
|
4. `O4b-B1.then` (0) → `O4b-B2.execute` (0) ;
|
|||
|
|
5. `GetArrayItem_1037.Output` → `O4b-V.Object` (0) ;
|
|||
|
|
6. `O4b-V.ReturnValue` (0) → `O4b-B2.Condition` (1) ;
|
|||
|
|
7. `O4b-B2.then` (0) → `O4b-B3.execute` (0) ;
|
|||
|
|
8. `GetArrayItem_1037.Output` → `O4b-G.self` (0) ;
|
|||
|
|
9. `O4b-G.Sex_Orgasm` (0) → `O4b-C.A` (0) ;
|
|||
|
|
10. `O4b-C.ReturnValue` (0) → `O4b-B3.Condition` (1) ;
|
|||
|
|
11. `O4b-B3.else` (1) → `O4b-R.execute` (0) — avec le marqueur : `O4b-B3.else` → `O4b-M.execute`, puis `O4b-M.then` → `O4b-R.execute` (lien 11 en deux liens) ;
|
|||
|
|
12. `GetArrayItem_1037.Output` → `O4b-R.self` (1) ;
|
|||
|
|
13. `O4b-R.then` (0) → `CallFunction_11423.execute` (0) ;
|
|||
|
|
14. `O4b-B1.else` (1) → `CallFunction_11423.execute` ;
|
|||
|
|
15. `O4b-B2.else` (1) → `CallFunction_11423.execute` ;
|
|||
|
|
16. `O4b-B3.then` (0) → `CallFunction_11423.execute` (jauge < 90 : pas de bonus).
|
|||
|
|
**Valeurs** : `set_pin_value` `O4b-C.B` = `90.0` (après le lien 9) ; marqueur : `O4b-M.InString` = `ORG4 bonus Endsex`, `O4b-M.bPrintToScreen` = `false`.
|
|||
|
|
**Relecture** : `IfThenElse_875.then` → `O4b-B1.execute` seul ; `CallFunction_11423.execute` ← **6 sources** (`CallFunction_32955.then`, `IfThenElse_189.then`, `O4b-B1.else`, `O4b-B2.else`, `O4b-B3.then`, `O4b-R.then`) ; `GetArrayItem_1037.Output` → 4 cibles (`CallFunction_6681.self`, `O4b-V.Object`, `O4b-G.self`, `O4b-R.self`) ; `VariableGet_3498.SexPersons` → 2 cibles ; les 3 `Condition` des Branches reliés ; `IfThenElse_875.else` → `MacroInstance_18.exec` inchangé.
|
|||
|
|
**Comptes O4b** : 8 nœuds (9) ; 1 coupure ; 16 liens (17) ; 1 valeur (3).
|
|||
|
|
|
|||
|
|
**Gardes** : `IsValidIndex(SexPersons, 0)` puis `IsValid(SexPersons[0])` avant la seule lecture de membre (`Sex_Orgasm`) et avant l'appel de l'événement (format G13 / G16, H3gS § 2.1) ; chaque `else` rejoint `AfterCumSpeed`, c'est-à-dire **exactement le chemin d'aujourd'hui**. Le test de valeur (`Sex_Orgasm < 90`) n'est pas une garde `Accessed None` mais la condition d'éligibilité.
|
|||
|
|
|
|||
|
|
### 2.4 Comptes et résultat attendu de l'IMPL
|
|||
|
|
| | sans marqueur | avec marqueur |
|
|||
|
|
|---|---|---|
|
|||
|
|
| Nœuds créés (O4a 3 + O4b 8 (+1)) | 11 | 12 |
|
|||
|
|
| `GI:EventGraph` (N0 = 6 253) | **6 264** | **6 265** |
|
|||
|
|
| Coupures | 2 | 2 |
|
|||
|
|
| Liens créés | 22 | 23 |
|
|||
|
|
| `set_pin_value` | 2 (`Rate`, `90.0`) | 4 (+ `InString`, `bPrintToScreen`) |
|
|||
|
|
Inchangés (VAL) : toutes les autres fonctions de GI ; `isSameAs` 11, `GetVariable` 53, `CallFunctionReturnBool` 594, `Action:EventGraph` 363 (H3gV:34).
|
|||
|
|
|
|||
|
|
### 2.5 Comportement avant / après (cas changés nommés)
|
|||
|
|
| Cas | Avant | Après |
|
|||
|
|
|---|---|---|
|
|||
|
|
| `Endsex`, `SexPersons[0].Sex_Orgasm ≥ 90` | scène terminée, **aucun bonus** ; 2 avertissements `PersonCumming` si `None` | **bonus** (O4b) : `OrgasmIrBoost` + `mood` +20 si `SexPersons[0]` est le joueur, sinon `attractiontoplayer` +3 (+6 si « Vaginal » et `WantsBabies`) si le joueur est dans la scène, sinon rien ; puis fin identique ; 0 avertissement → **changement voulu** |
|
|||
|
|
| `Endsex`, jauge < 90 | fin ; 2 avertissements si `None` | fin identique ; 0 avertissement ; pas de bonus |
|
|||
|
|
| `Endsex`, `SexPersons` vide ou `[0]` invalide | (cas non rencontré) | `else` → chemin d'aujourd'hui |
|
|||
|
|
| `Finish` (« Cum on … ») puis `Endsex` | 1 bonus (Finish) ; `Endsex` sans bonus | idem : `Person::Cum` remet `Sex_Orgasm` à 0 (P-STG:17282-17287) → jauge < 90 → **pas de double bonus** |
|
|||
|
|
| Orgasme automatique à 100, puis `Endsex` | idem | idem (même remise à 0) |
|
|||
|
|
| Scène suivante, `Endsex` aussitôt | — | jauge remise à 0 au démarrage de la scène par `UpdateSexLikes` (P-STG:15804-15818 ; appelé en boucle sur `SexPersons`, GI-P2:27418-27421, 12385-12391, avec `SexOn := true` voisin, 6896-6899 ; **estimé** : événement propriétaire de la boucle non nommé) → **pas de bonus gratuit en boucle** |
|
|||
|
|
| `Endsex` après un orgasme antérieur (`PersonCumming` périmé mais valide) | `Rate` selon le dernier jouisseur | inchangé (garde vraie) |
|
|||
|
|
| `PersonCumming` détruit, en attente de ramasse-miettes (`IsValid` faux, pointeur non nul) | lit les champs périmés | `Rate = 0.25` (écart théorique, très rare ; seul cas de O4a qui change une valeur) |
|
|||
|
|
| `Exhausted` → `GI.Cum` (minuterie 10 s) avec `PersonCumming` `None` | 2 avertissements, `Rate = 0.25` | 0 avertissement, `Rate = 0.25` |
|
|||
|
|
| Bonus **sans orgasme** | non | **oui, par conception** : terminer à ≥ 90 compte comme une jouissance ; sans effet d'orgasme (pas de remise à 0, pas de particule, pas de texte) → Q-ORG4-1 |
|
|||
|
|
| Persons autres que `[0]` (partenaire, scènes à plusieurs) | pas de bonus | pas de bonus (comme `Finish`, qui ne vise que `Persons[0]`) → option (c) de Q-ORG4-1 |
|
|||
|
|
Le cas « tous ceux à 100 » est vide : l'orgasme à 100 se déclenche dans le même appel que la mise à jour de la jauge (`FClamp` puis `== 100.0` → `Cum()`, P-STG:15896-15901, 16030-16043), donc aucune jauge ne vaut 100 au moment d'un clic (établi par la lecture ; AUD § 2).
|
|||
|
|
|
|||
|
|
## 3. Repli
|
|||
|
|
- Avant écriture : instantané `.\Tools\Snapshot.ps1 -Lot STE-ORG4` (P3), MD5 de départ (P2).
|
|||
|
|
- **Aucun `save_assets` tant que `compile_blueprint` n'est pas à 0 diagnostic.** Échec avant enregistrement : fermer l'éditeur sans enregistrer (le `.uasset` reste l'instantané), contrôler le MD5, rapporter. Aucun correctif improvisé.
|
|||
|
|
- Après enregistrement, lien relu différent, `type_id` introuvable (P5), nœud inattendu, P0 contraire : arrêt, rapport ; puis, sur décision de l'orchestrateur, éditeur fermé : `.\Tools\Restore.ps1 -Lot STE-ORG4 -Only Content\BPs\GI.uasset -WhatIf`, puis sans `-WhatIf` ; MD5 = valeur de P2. Un `Restore` de GI rend l'état de l'instantané : G16 et B7-a (déjà dans le fichier à l'entrée) sont conservés, aucune autre écriture de GI ne doit être intercalée.
|
|||
|
|
- **Repli de conception** : (i) P0 contraire ou Q-ORG4-1 = (a) → **O4a seul** (3 nœuds, EventGraph N0 + 3) ; (ii) O4b-C non créable → inverser avec `>=` (§ 2.3) ou arrêt ; (iii) le marqueur gêne → l'omettre (il est retirable et ignoré en Shipping : `DevelopmentOnly`, § 6).
|
|||
|
|
- Après commit (gardien) : `git revert` du commit du ticket STE-ORG4. **Couplage de commit** : `GI.uasset` est un binaire unique qui porte déjà G16 (commit différé jusqu'au verdict COMMUN-2, STE-TACHES.md:31) et B7-a (STG) ; ces trois changements partent dans le même fichier, donc dans un même commit ou dans l'ordre imposé par le gardien (R-ORG4-2).
|
|||
|
|
|
|||
|
|
## 4. Risques R#, questions Q#
|
|||
|
|
- **R-ORG4-1** : la valeur `ForceEnd = true` de l'appel `GI.Cum` de `SexAction` est **déduite** (§ 1.1 a-c), pas lue. Si elle est fausse, O4b ne s'exécute jamais : la VAL statique (V5) passe quand même, seul l'essai en jeu (V6-S1) le révèle. → P0 bloquant avant O4b.
|
|||
|
|
- **R-ORG4-2** : `GI.uasset` partagé : G16 (STE-H3g) et B7-a (STG) non commités dans le même binaire ; instantané à l'entrée ; commit conjoint ou ordonné ; ne jamais restaurer GI depuis un instantané antérieur à l'un d'eux.
|
|||
|
|
- **R-ORG4-3** : noms et indices de broches des nœuds à créer inconnus (`Classe|Person|ObtenirSexOrgasm`, catégorie de `DéfinirRate`, `GiveOrgasmReward`) : P5 / P7 ; type_id non relu = arrêt.
|
|||
|
|
- **R-ORG4-4** : `GiveOrgasmReward` affiche ses `ModifyStat` (`NoDisplay` faux, P-STG:16070-16087) à l'image même où `EndSex` défait la scène (bascules d'interface, STE-H8-DIAG) : le texte peut s'afficher très brièvement ou être masqué ; l'effet sur la stat existe quand même. V6 le fait constater (observation) ; aucune trace de journal n'existe (§ 7, V6).
|
|||
|
|
- **R-ORG4-5** : ré-entrée de l'événement `Cum` si l'on appelait `Person::Cum` depuis `GI::Cum` (§ 2.3) ; écartée par conception.
|
|||
|
|
- **R-ORG4-6** : articulation avec **STE-ORG5** (reconstruction de la grille v5.26) : O4b appelle le **même** `GiveOrgasmReward` ; si ORG5 y ajoute `PopulateBonusRewards` (AUD § 9.3), une grille s'ouvrirait à l'image de la fin de scène. À traiter dans la SPEC ORG5 (sauter la grille depuis `Endsex`, ou accepter) ; pas de double bonus tant que O4b ne s'ajoute qu'à `Endsex` (jauge ≥ 90) et non à `Finish`.
|
|||
|
|
- **R-ORG4-7** : `PersonCumming` lu ailleurs que dans l'EventGraph de GI (autres fonctions de GI, UI) : non lu (§ 2.0 : P4 peut ajouter `find_nodes {graph, title:"PersonCumming"}` si l'outil le permet) ; O4a ne garde que les deux lectures connues.
|
|||
|
|
- **R-ORG4-8** : le dump de Person (14:08) précède la dernière sauvegarde de Person (17:42) : la chaîne `GiveOrgasmReward` a pu changer ; P7 et la VAL (V6) le couvrent.
|
|||
|
|
- **R-ORG4-9** : autre appelant inconnu de `GI.Cum` avec `ForceEnd = true` (widget non dumpé) : il recevrait aussi le bonus à jauge ≥ 90 (souhaitable : fin de scène).
|
|||
|
|
- **Q-ORG4-1 (utilisateur, avant O4b)** : qui reçoit le bonus quand on termine par `Endsex` ?
|
|||
|
|
| Option | Description | Pour | Contre |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| (a) personne | O4a seul | conception d'origine (`Endsex` ≠ orgasme) ; aucun bonus gratuit | l'utilisateur reste sans bonus à `Endsex` |
|
|||
|
|
| **(b) `SexPersons[0]` si jauge ≥ 90** (recommandée) | O4a + O4b | même éligibilité que `Finish` (PC-STE:6128-6142) ; bonus seul ; pas de double bonus ni de farm (jauge remise à 0 par `Cum` et par le démarrage de scène) | « bonus sans orgasme » ; la partenaire (index 1) n'est pas servie |
|
|||
|
|
| (c) chaque participant à ≥ 90 | boucle `ForEachLoop` sur `SexPersons` (macro vue en `MacroInstance_806`, GI-P2:7094-7100 ; `type_id` à relever) | plus juste pour deux jouisseurs | +5 nœuds environ, non spécifié ici ; autre SPEC |
|
|||
|
|
| (d) `Person::Cum` complet avant `GI.Cum` | côté `SexAction` (illisible) | effets complets | ré-entrée si fait dans GI ; SexAction non dumpé |
|
|||
|
|
Recommandation : **(b)**. Question jumelle, **Q-ORG4-2** : seuil 90 (celui du message rouge, P-STG:17363-17367, et de `Finish`) ou autre ?
|
|||
|
|
- **Q-ORG4-3 (orchestrateur)** : marqueur de trace `ORG4 bonus Endsex` (1 nœud, ignoré en Shipping) : oui (recommandé : V6 n'a aucune autre preuve de journal, § 7) ou non.
|
|||
|
|
- **Q-ORG4-4 (orchestrateur)** : UE-GO pour P0 (dump de `SexAction`) puis pour l'IMPL, gel annoncé, ticket du gardien (R-ORG4-2).
|
|||
|
|
- **Q-ORG4-5 (orchestrateur)** : O4a seul pour l'alpha si Q-ORG4-1 tarde (3 nœuds, sans changement de comportement, supprime F2).
|
|||
|
|
|
|||
|
|
## 5. Interdits
|
|||
|
|
- Aucune modification de Person (aucun `save_assets` de Person), de SexAction, de PC, de `GetVariable`, `CallFunctionReturnBool`, `isSameAs`, `Action`, du C++, des scènes et modules ; aucune autre branche de `GI::Cum` que `IfThenElse_875.then` ; `AfterCumSpeed` modifié par O4a seulement (3 nœuds).
|
|||
|
|
- **Pas d'appel de `Person::Cum` depuis GI** ; aucun `FunctionResult` créé ; pas de `delete_node` ; pas de AND / OR / Select purs ; pas de `type_id` non relu (P5) ; pas d'écriture HyperAIStudio (`lp-mcp` § 1 règle 1) ; outils Epic seulement.
|
|||
|
|
- Pas d'IMPL de O4b sans P0 conforme et Q-ORG4-1 répondue ; pas d'IMPL sans P1 à P7 ; pas d'IMPL entrelacée avec une autre écriture sur GI.
|
|||
|
|
- Pas de commit par l'agent : ticket au gardien (`lp-repo`).
|
|||
|
|
|
|||
|
|
## 6. Valeurs moteur lues dans le moteur installé (UE = `D:\Game\Launcher\Engine\UE_5.8\Engine\Source\`)
|
|||
|
|
Relu aujourd'hui :
|
|||
|
|
- `UKismetSystemLibrary::PrintString` est `DevelopmentOnly` : `UE`Runtime\Engine\Classes\Kismet\KismetSystemLibrary.h:565-566 (le marqueur est ignoré en Shipping, joué en Development).
|
|||
|
|
- `UKismetMathLibrary::SelectFloat(double A, double B, bool bPickA)` : « If bPickA is true, A is returned, otherwise B is » : `UE`Runtime\Engine\Classes\Kismet\KismetMathLibrary.h:3850-3852.
|
|||
|
|
Repris de H3gS § 6 (relus le 2026-10-13, **non relus aujourd'hui**) : `IsValid(const UObject*)` = non nul et non en attente de destruction (`KismetSystemLibrary.h:126-128`) ; `GenericArray_IsValidIndex` sans message (`KismetArrayLibrary.cpp:583-595`) ; `GenericArray_Get` hors plage → message `Attempted to access index …` et valeur par défaut (`KismetArrayLibrary.cpp:459-482`) ; `Accessed None trying to read …` (`ScriptCore.cpp:3213-3216`, valeur effacée `3234-3245`).
|
|||
|
|
**Non lu** (estimé) : le stockage des paramètres d'un événement personnalisé dans la trame de l'ubergraph (raison de ne pas ré-entrer dans `Cum`, § 2.3) — à lire avant de s'en servir comme preuve, hors besoin de cette SPEC.
|
|||
|
|
|
|||
|
|
## 7. Critères de VAL (commande → attendu)
|
|||
|
|
|
|||
|
|
### V5 — VAL statique (éditeur fermé, `.\Tools\UeState.ps1 -Kind Editeur` = 0)
|
|||
|
|
1. **Dump** : `.\Tools\RunCommandlet.ps1 -Lot STE-ORG4V -Commandlet LPDumpFunction -Args '-BP=GI -Fn=EventGraph -Pins -Exec' -EtatDir "D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE"` → en-tête `=== GI :: EventGraph (6264 noeuds) ===` (6265 avec marqueur) ; et :
|
|||
|
|
- `CustomEvent_702.then` → `O4a-B.execute` seul ; `O4a-B.then` → `VariableSet_9760.execute` seul ; `O4a-B.else` → `O4a-S.execute` ; `O4a-S.Rate` = 0.25 ; `O4a-S.then` → `CallFunction_960.execute` ; `CallFunction_960.execute` ← `VariableSet_9760.then`, `O4a-S.then` ; `VariableGet_720.PersonCumming` → `VariableGet_721.self`, `VariableGet_722.self`, `O4a-V.Object` ; `O4a-B.Condition` ← `O4a-V.ReturnValue` ;
|
|||
|
|
- `IfThenElse_875.then` → `O4b-B1.execute` seul ; `IfThenElse_875.else` → `MacroInstance_18.exec` inchangé ; `CallFunction_11423.execute` ← 6 sources (§ 2.3) ; `O4b-I.TargetArray` ← `VariableGet_3498.SexPersons` ; `IndexToTest` = 0 ; `O4b-V.Object`, `O4b-G.self`, `O4b-R.self` ← `GetArrayItem_1037.Output` ; `O4b-G.Sex_Orgasm` → `O4b-C.A` ; `O4b-C.B` = 90 ; `O4b-B3.else` → `O4b-R.execute` (ou `O4b-M`) ; `O4b-B3.then`, `O4b-B2.else`, `O4b-B1.else`, `O4b-R.then` → `CallFunction_11423.execute` ; les 4 Branches de O4a / O4b ont leur `Condition` reliée.
|
|||
|
|
Non-régression (un par un) : `-Fn=isSameAs` → 11 ; `-Fn=GetVariable` → 53 ; `-Fn=CallFunctionReturnBool` → 594 ; `-BP=Action -Fn=EventGraph` → 363 (H3gV:34).
|
|||
|
|
2. **Diff indépendant** : `python -I Tools\DiffRemplacementNoeuds.py <dump P1> <dump après> <profil>` → seuls les nœuds et liens du § 2.2-2.4 ; « pins modifiés sur nœuds communs » = `CustomEvent_702`, `VariableSet_9760`, `CallFunction_960`, `VariableGet_720`, `IfThenElse_875`, `CallFunction_11423`, `VariableGet_3498`, `GetArrayItem_1037` (8) et aucun autre.
|
|||
|
|
3. **Compilation** : `compile_blueprint … warnings_as_errors:true` → `null`, journal de l'éditeur sans Error / Warning pour GI ; `CompileAllBlueprints` éditeur fermé : BP `/Game/` du projet **0 erreur** (critère requalifié le 2026-10-13, `CC_Shaders` à part ; ligne de référence de H3gV, citée par STE-TACHES.md:31 : « 25/3/55/420 ») ; `LPTestStringCompat` **3120 / 0 / 60** (`lp-validate`).
|
|||
|
|
4. **Empreintes** : `md5sum Content/BPs/GI.uasset` noté ; `md5sum Content/BPs/Person.uasset` = `8668a47c627f7a5254910cf0ac33b12a` et `Content/UI/SexAction.uasset` = `a8705f7fbe1fde1daba0464bfc9ff9b5` (inchangés) ; Room : valeur relevée à l'entrée = à la sortie ; `git status --short -- Content` : aucun fichier de plus que ` M` GI, Person, Room.
|
|||
|
|
|
|||
|
|
### V6 — essai en jeu (build Development empaqueté par BUILD, **même ligne de commande que HJ** : `-ScriptStackOnWarnings -LPHitchLog`, HJ:291 ; UE-GO / BUILD-GO de l'orchestrateur)
|
|||
|
|
**Ce que le journal ne montre pas** : `ModifyStat` ne laisse aucune ligne. Dans HJ, un `Endsex` a eu lieu (HJ:9242) et `GI::EndSex` applique `arousal -50` et `mood +50` à chaque participant (GI-P2:7803-7811) ; Grep `attractiontoplayer|\bmood\b` sur HJ → aucune ligne ; Grep `\barousal\b` sur HJ → aucune ligne (contrôle positif : `Endsex|ORG4` sur HJ → 1 ligne). Le critère « trace `mood` / `attractiontoplayer` » de la fiche n'est donc **pas tenable par le journal** : preuve = marqueur O4b-M (Q-ORG4-3) **et** observation à l'écran (texte de stat de `ModifyStat`, `NoDisplay` faux) rapportée par l'utilisateur.
|
|||
|
|
**Parcours à jouer** (une scène MF avec le joueur ; noter qui est `SexPersons[0]` : l'homme / la personne au pénis, joueur ou PNJ) :
|
|||
|
|
- **S1** (bonus) : laisser monter la jauge de `SexPersons[0]` entre 90 et 100 (texte rouge « Close to cumming… » visible, seuil P-STG:17363-17367), puis cliquer « Finish having sex » (pas une animation « Cum on … »). Attendu : la scène se termine dans la même image ; texte de stat du bonus à l'écran (`mood` +20 si c'est le joueur ; `attractiontoplayer` +3 / +6 sur le PNJ si le joueur est dans la scène), en plus de ceux de `EndSex` ; marqueur dans le journal.
|
|||
|
|
- **S2** (témoin sous le seuil) : démarrer une scène, cliquer « Finish having sex » aussitôt (jauge < 90). Attendu : fin de scène, aucun texte `mood +20` / `attractiontoplayer`, aucun marqueur, 0 avertissement.
|
|||
|
|
- **S3** (pas de double bonus) : jauge ≥ 90, choisir une animation « Cum on … » (bonus 1 par `Person::Cum`), puis cliquer « Finish having sex » aussitôt. Attendu : pas de second bonus, aucun marqueur pour ce clic, 0 avertissement.
|
|||
|
|
- **S4** (orgasme à 100) : laisser la jauge atteindre 100 (orgasme automatique), puis « Finish having sex ». Attendu : comme S3.
|
|||
|
|
**Greps sur le journal du jeu** (mode `count`, fichier nommé ; base = HJ) :
|
|||
|
|
| Motif | HJ (1 clic `Endsex`) | Attendu |
|
|||
|
|
|---|---|---|
|
|||
|
|
| `Endsex \(Animation String\)` | 1 | = nombre de clics (S1 à S4 : 4 si une scène par cas) — **preuve que le parcours est rejoué** (sans elle, un 0 ne prouve rien) |
|
|||
|
|
| `Accessed None trying to read \(real\) property PersonCumming` | 2 | **0** |
|
|||
|
|
| `ORG4 bonus Endsex` (si marqueur) | 0 | **1** (S1 seul) |
|
|||
|
|
| `GiveOrgasmReward\|OrgasmIrBoost` (piles d'avertissement) | 0 | **0** |
|
|||
|
|
| `fatal\|Unhandled\|Critical\|Assertion` | 0 | **0** |
|
|||
|
|
| `LogScript: Warning: Accessed None` | 13 | ≤ 11 (indicatif : −2 pour F2 ; le reste dépend du parcours) |
|
|||
|
|
Non-régression : `.\Tools\LogStats.ps1 -Compare <journal>,<HJ>` : aucune famille nouvelle ; G13 et G16 intacts (`isCreatureType` → 0).
|
|||
|
|
**Limites** : l'effet réel des stats n'est vu qu'à l'écran ; le cas `PersonCumming` périmé mais valide (un `Endsex` après un orgasme) est couvert par S3 et S4 (0 avertissement avant comme après, `Rate` inchangé) ; le cas « détruit en attente de ramasse-miettes » n'est pas rejoué.
|
|||
|
|
|
|||
|
|
Fichiers à commiter (dépôt jeu, branche `ue5.8`, ticket au gardien) :
|
|||
|
|
- A `Docs/Migration/etat/ST/STE/STE-ORG4-SPEC.md`
|
|||
|
|
|
|||
|
|
Tours : 29 / 45 (compte de l'agent, écriture comprise ; `python -I Tools/FicheStats.py --lot STE` fait foi)
|
|||
|
|
|
|||
|
|
## Constats
|
|||
|
|
- **Lectures qui manquent pour O4b** (commandes données, non lancées) : P0 (`SexAction` EventGraph) ; facultatives : refresh du dump de PC (`-BP=PC -Fn=EventGraph`, celui de 10-10 précède CAM-B1) ; autres fonctions de GI lisant `PersonCumming` (R-ORG4-7).
|
|||
|
|
- Commandes de lecture (Grep / Read sauf mention) et comptes bruts :
|
|||
|
|
- Grep `ForceEnd` sur le dossier `E\ST\STE\dumps` → `No matches found` alors que GI-P2 contient la chaîne (GI-P2:10806) : **les `.txt` de `etat\` sont ignorés par ripgrep même avec le dossier en `path`** ; il faut nommer le fichier (piège déjà noté, H3fD « Constats »). Les Grep ci-dessus nomment tous le fichier.
|
|||
|
|
- Grep `ForceEnd` (fichier nommé) : PC-STE → 0 ; `E`ST\STA\dumps\SexInterface__EventGraph.txt` → 0 ; `L6f_dump_Scene.txt` → 0 ; `E`ST\STE\dumps\Room__EventGraph_V5.txt` → 0 ; L6f-G → 58572, 58574, 58598, 61588, 61590, 72019, 72237 ; `L6f_dump_Person.txt` → 37160, 37168, 37202 (`false`).
|
|||
|
|
- Grep `appel [A-Za-z_?]+::(Cum|EndSex|AfterCumSpeed|GiveOrgasmReward)\(\)` sur GI-P2 → 10840, 10905, 14564 ; sur P-STG (`Cum|EndSex|GiveOrgasmReward`) → 15958, 15966, 16000, 16040, 16107 ; sur PC-STE → 0.
|
|||
|
|
- Grep `variable 'Sex_Orgasm'` sur GI-P2 → 0 ; sur P-STG (`VariableSet_N`) → 15807, 15873, 17282 ; `UpdateSexLikes` : P-STG:15804 (définition) ; GI-P2:27418 (seul appelant) ; `PersonCummedOn` : 4 lectures, 0 écriture dans GI-P2 (18952-18975).
|
|||
|
|
- Grep `Endsex|ORG4` sur HJ → 1 ; `attractiontoplayer|\bmood\b` → 0 ; `\barousal\b` → 0 ; J6 `Endsex|PersonCumming|Accessed None` → 1 ligne `Endsex` (J6:2849), 0 ligne `PersonCumming`.
|
|||
|
|
- Bash `grep -a -c` sur `Content/UI/SexAction.uasset` : `Endsex` 2 ; `ForceEnd` 1 ; `NoPregCheck` 1 ; `PlayAppropriateSexAnimation` 1 (comptes de **lignes** contenant la chaîne ; présence d'un nom, pas valeur d'une broche).
|
|||
|
|
- Le résumé `.txt` d'un `RunCommandlet` rangé sous `etat\` (ex. `STE-H3gV_LPDumpFunction_*.txt`) n'est pas le dump complet (compteurs de lignes d'avertissement dédoublonnées) ; le dump complet est dans `Saved\Logs\portage\` ou dans un fichier `__EventGraph_*.txt` produit à part.
|
|||
|
|
- Hors périmètre, noté : F-ORG2 (AUD) `GI::EndSex` donne `mood +50` / `arousal -50` à chaque participant indépendamment de l'orgasme (GI-P2:7803-7811) ; l'« ancien modèle `ToCum` » (AUD § 6 P5) n'est pas concerné.
|
|||
|
|
- Lecture seule respectée ; un seul fichier écrit (ce livrable, non suivi). Aucun nom d'utilisateur ni chemin de profil cité.
|
|||
|
|
|
|||
|
|
## Décisions de l'utilisateur (2026-10-14, session STE)
|
|||
|
|
- Q-ORG4-1 : **chaque participant**, l'un après l'autre, reçoit un bonus à `Endsex` quand sa jauge dépasse **90 pour un homme** et **100 pour une femme** (réponse libre de l'utilisateur ; la réponse « 90 » à Q-ORG4-2 vaut pour les hommes). Option (c) avec seuil selon le sexe : **SPEC complémentaire O4c à écrire** (boucle sur `SexPersons`, test du sexe, seuils 90 / 100), en remplacement de O4b.
|
|||
|
|
- Q-ORG4-3 (orchestrateur) : marqueur de trace **oui**. Q-ORG4-5 : O4a peut partir seul si O4c tarde.
|
|||
|
|
|
|||
|
|
## Règle commune ORG4 / ORG5 (Big Boss, 2026-10-14)
|
|||
|
|
- Pour **un même orgasme**, une personne reçoit au plus **une fois** le bonus de base (`GiveOrgasmReward`) et au plus **une fois** les récompenses ORG5 (3 au plus) ; le cumul base + ORG5 est voulu, le même bonus deux fois non.
|
|||
|
|
- Orgasme réel (`Person::Cum`, jauge à 100 ou choix « Cum on … ») : `GiveOrgasmReward` une fois (chemin existant) ; ORG5 une fois, déclenché par l'incrément de `Sex_OrgasmCounts` (accroche H1).
|
|||
|
|
- `Endsex` (O4c) : `GiveOrgasmReward` une fois par participant éligible (homme > 90, femme = 100), **sans** `Person::Cum` : `Sex_OrgasmCounts` inchangé, donc **pas de récompense ORG5** à `Endsex` ; un participant qui vient de jouir a sa jauge remise à 0 par `Cum` et n'est pas éligible : pas de second bonus de base.
|
|||
|
|
- Toute IMPL qui change l'un de ces déclencheurs relit cette règle et la VAL la contrôle (V6 : un orgasme = 1 marqueur de base + au plus 1 ligne ORG5 par personne).
|