LifePlay-Revival/Docs/Migration/etat/ST/STE/STE-ORG4c-SPEC.md
edujiro5972 8084622450 LifePlay UE 5.8 : état de développement au 2026-10-19
Tickets : REP1-T4

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 22:57:42 +02:00

331 lines
60 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Fiche STE-ORG4c — Niveau N3 — Modèle prévu (modèle de l'agent lp-cart) | utilisé claude-sonnet-5-5 — Agent lp-cart — Skills lp-mcp (lu : `.claude\skills\lp-mcp\SKILL.md`, lecture seule), sk-protocol (invoqué), ue-cpp-build, lp-commandlets, lp-paths (préchargés avec l'agent)
# STE-ORG4c-SPEC : bonus d'orgasme à `Endsex` pour chaque participant, seuil selon le sexe (O4c, remplace O4b) (2026-10-14, complété le 2026-10-14 : décisions de l'utilisateur intégrées, Q-ORG4c-2 = `IsMale` OU `Genital == 'Penis'`)
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 et comportement = § 1 et § 2.5 ; O4c au geste près, comptes = § 2.3 et § 2.4 ; règle commune ORG4 / ORG5 = § 2.6 ; repli = § 3 ; Q# = § 4 ; V5 / V6 mis à jour = § 7. Lecture seule stricte (Read, Grep, Glob ; Bash pour `git rev-parse`, `md5sum`, `git status`) ; aucun éditeur, MCP, commandlet, build ni jeu ; un seul fichier écrit : ce livrable.
## Annonce en tête
- **O4c remplace O4b** de `STE-ORG4-SPEC.md` (§ 2.3) : les nœuds `O4b-*` ne sont **pas** créés. **O4a** (garde `PersonCumming` dans `AfterCumSpeed`) est **reprise sans changement** de `STE-ORG4-SPEC.md` § 2.2 (3 nœuds, 1 coupure, 6 liens, 1 valeur) ; elle reste indépendante et peut partir seule (Q-ORG4-5).
- **Person, SexAction, PC ne sont pas touchés** ; **GI est touché** (`Content\BPs\GI.uasset`, graphe `EventGraph` seul), qui porte déjà G16 (STE-H3g) et B7-a (STG) non commités (R-ORG4-2 de `STE-ORG4-SPEC.md`).
- **Décisions de l'utilisateur intégrées** (section finale « Décisions », 2026-10-14) : seuil femme 100 gardé (Q1) ; **« homme » = `IsMale` OU `Genital == 'Penis'`** (Q2, la règle de « Close to cumming ») ; `>= 90` et `>= 100` (Q3) ; garde `IsValid` par élément oui (Q4) ; deux libellés de marqueur, pas de marqueur à l'orgasme réel (Q5).
- **Statut : exécutable par MCP**, **sous la condition P0** (lecture de `SexAction` ; le dump n'existe toujours pas : Glob `**\*SexAction*` sous `etat\ST\STE` → aucun fichier). **Sept type_id n'ont jamais été créés par MCP dans ce projet** : `Utilities|Array|ForEachLoop`, `Classe|Person|ObtenirIsMale`, `Classe|Person|ObtenirSexOrgasm`, `Classe|Person|ObtenirGenital`, `Classe|Person|GiveOrgasmReward`, la conversion Texte vers chaîne (`Conv_TextToString`) et l'égalité de chaînes (`EqualEqual_StriStri`) : ils se relèvent par `find_node_types` avant tout geste (§ 2.1). Relus **et** déjà créés : Branche, `IsValid` pur, `Inférieurà(<)`, `Développement|PrintString`, `Math|Booléen|ORBoolean`.
- **Trois constats qui changent la lecture de la décision** (détails § 1.2) :
1. « homme » se lit par **`IsMale` OU `Genital == 'Penis'`** : exactement la combinaison du jeu pour « Close to cumming » (P-STG:17340-17359), et GI en lit déjà une variante sur `SexPersons[0]` (GI-P2:18904-18931). `Genital` est un **Texte** : conversion en chaîne puis égalité de chaînes (précédent identique dans GI et dans Person).
2. Le seuil **femme = 100 n'est atteignable à aucun moment de l'interface** : à `Sex_Orgasm == 100.0` l'orgasme automatique se déclenche dans le même appel et remet la jauge à 0. La branche « non homme » de O4c est écrite fidèlement à la décision (gardée) mais **ne s'exécute pas en pratique** (Q-ORG4c-1, R-ORG4c-2). V6 ne peut pas la rejouer.
3. Le corps de boucle n'a **pas à rejoindre** `AfterCumSpeed` : un chemin qui s'arrête dans le corps passe à l'élément suivant (précédent dans le même graphe, § 1.2 F6) ; seule la sortie `Completed` rejoint la suite existante.
Abréviations (chemins absolus) : **E** = `D:\Game\LifePlay-master 5.8\Docs\Migration\etat\` ; **ORG4S** = E`ST\STE\STE-ORG4-SPEC.md` ; **ORG5S** = E`ST\STE\STE-ORG5-SPEC.md` ; **GI-P2** = E`ST\STE\dumps\GI__EventGraph_P2.txt` (6 249 nœuds, en-tête ligne 1) ; **P-STG** = E`ST\STG\dumps\Person__EventGraph.txt` ; **PC-STE** = E`ST\STE\dumps\PC__EventGraph.txt` ; **AUD** = E`ST\STE\STE-ORG-AUDIT.md` ; **H3gI** = E`ST\STE\STE-H3g-IMPL.md` ; **H5bC** = E`ST\STE\STE-H5b-C0.md` ; **H10I** = E`ST\STE\STE-H10-IMPL.md` ; **H10G1** = E`ST\STE\STE-H10-GI1-IMPL.md` ; **H10G2** = E`ST\STE\STE-H10-GI2-IMPL.md` ; **B7aI** = E`ST\STG\STG-B7a-IMPL.md` ; **B2PI** = E`ST\STG\STG-B2P-IMPL.md` ; **CAMB2g** = E`CAM\CAM-B2g-IMPL.md` ; **UE** = `D:\Game\Launcher\Engine\UE_5.8\Engine\Source\`.
## État relevé à l'entrée de cette SPEC (Bash, lecture, 2026-10-14)
| Commande | Sortie |
|---|---|
| `git -C "D:/Game/LifePlay-master 5.8" rev-parse --short HEAD` | `0745917` |
| `md5sum …/Content/BPs/GI.uasset` | `e64b5b37c9ef0db7735de0d6e3bd7c1c` (= valeur de ORG4S, GI inchangé depuis) |
| `md5sum …/Content/BPs/Person.uasset` | `8668a47c627f7a5254910cf0ac33b12a` (= ORG4S) |
| `md5sum …/Content/UI/SexAction.uasset` | `a8705f7fbe1fde1daba0464bfc9ff9b5` (= ORG4S) |
| `git -C … 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, PC, Person, Room ; SexAction non listé |
| Grep `^=== GI` sur GI-P2 | `1:=== GI :: EventGraph (6249 noeuds) ===` et `30177:=== GI :: EventGraph (6249 noeuds) ===` (le fichier contient **deux blocs** à en-tête identique : liste des nœuds avec broches, puis liste de l'exécution) |
**Écart à ORG4S** : `PC.uasset` est maintenant ` M` (ORG4S : « SexAction et PC non listés »). PC n'est pas touché par O4c et n'est lu qu'à titre descriptif (dump PC-STE du 2026-10-10, antérieur) : l'écart ne conditionne pas ce correctif, mais le dump de PC est périmé (R-ORG4c-8). **N0** (nœuds de `GI:EventGraph` à l'entrée) = **6 253** (repris de ORG4S, état relevé, ligne 27 ; chaîne H3g puis B7-a ; **non relu à la source aujourd'hui**, P1 le refait). Le dump GI-P2 (6 249) reste valable pour les nœuds du chemin `Cum` (aucun n'a changé de nom : ORG4S, même ligne).
## 1. Objectif mesurable
### 1.1 Rappel de la cause (renvoi à ORG4S § 1.1)
`Endsex` appelle `GI::Cum` **directement** avec (estimé fort, P0) `ForceEnd = true`, sans passer par `Person::Cum` : ni `GiveOrgasmReward` ni l'incrément de `Sex_OrgasmCounts` ne sont atteints. Le chemin dans GI : `CustomEvent_4245` (`Cum`) puis `IfThenElse_875` (`Condition` = `ForceEnd`, GI-P2:14554-14558) puis `then` vers `CallFunction_11423` (`AfterCumSpeed`, GI-P2:10905-10908) puis la suite jusqu'à `EndSex` (`IfThenElse_876`, GI-P2:14559-14567). O4c s'insère entre `IfThenElse_875.then` et `CallFunction_11423.execute`.
### 1.2 Faits relevés pour O4c (établi sauf mention)
| # | Fait | Source |
|---|---|---|
| F1 | Le sexe d'une personne est porté par la **variable booléenne `IsMale`** de Person ; GI la lit par un `VariableGet` dont `self` est une référence Person (`IsMale` vers `BooleanAND.B`, `self` ← `PersonCumming`). Elle est écrite par le chargen (`PlayerChangeGender`, paramètre `NewIsMale`). Aucune variable `IsFemale` ni `Gender` dans GI-P2 ni dans P-STG (les occurrences de GI-P2 sont `GenderBender`, `GenderOnly`, `SortSexPersonsByGender`, `CheckCbeGenderModel`, un champ de structure `isMale_5_…`). | GI-P2:28056-28063 ; GI-P2:3830-3835, 973 ; Grep `variable '(IsMale|IsFemale|Gender|…)'` sur GI-P2 → 25 lignes, toutes `IsMale` ; Grep `IsFemale|Gender|isMale|HasPenis|HasVagina|Transgender|Futa|Hermaph|Intersex` sur P-STG → aucune correspondance ; Grep `variable '(IsMale|Sex_Orgasm|…)'` sur P-STG → 43 lignes |
| F2 | Le jeu connaît une seconde notion : `Genital` (**Texte**) = `'Penis'`. Il l'utilise **avec** `IsMale` : `IsMale OU (Genital == 'Penis')` pour le texte « Close to cumming » (`TogglePulloutNotification`, seuil `Sex_Orgasm >= 90`, index 0 de `SexPersons` seulement, filtres MF / MM / FF+tag `Shemale`), et `Genital == 'Penis'` seul pour `NoPregCheck` dans `Cum`. **C'est la règle retenue par l'utilisateur pour « homme » (Q2).** | P-STG:17340-17359, 17360-17367, 17376-17396, 17408-17417 ; P-STG:15942-15957 |
| F3 | `Sex_Orgasm` est un **double** (`GreaterEqual_DoubleDouble`, `Less_DoubleDouble`, `EqualEqual_DoubleDouble`), borné à [0, 100] par `FClamp`. | P-STG:17363-17367 ; P-STG:16126-16129 ; P-STG:16030-16033 ; P-STG:15896-15901 |
| F4 | **Orgasme automatique à 100 pour tout le monde** : `UpdateOeChange` écrit `Sex_Orgasm` (somme clampée), écrit `Sex_Energy`, appelle `TogglePulloutNotification`, puis `Sex_Orgasm == 100.0` vrai → `Cum()`, le tout de façon synchrone. Écrivains de `Sex_Orgasm` dans P-STG : trois seulement, valeurs `0.0` (début de scène), somme clampée, `0.0` (dans `Cum`). Aucun écrivain dans GI-P2 (0 occurrence de `Sex_Orgasm` : Grep `variable 'Sex_Orgasm'`), ni dans PC-STE, ni dans `SexInterface__EventGraph.txt`, ni dans `GI__PlayAppropriateSexAnimation.txt` (Grep `VariableSet_\d+ +variable 'Sex_Orgasm'` → 0 dans chacun des trois). Conclusion : une jauge à 100 est remise à 0 dans l'image où elle y arrive → **à `Endsex`, `Sex_Orgasm == 100.0` est inatteignable** (estimé fort : seuls les graphes dumpés sont lus ; les fonctions annexes de Person et les mods ne le sont pas). | écrivains : P-STG:15807-15812 (`0.0`), 15873-15876 (somme), 15896-15901 (`FClamp`), 17282-17287 (`0.0`) ; chaîne : P-STG:15874-15875, 15890-15892, 17315-17318, 16035-16043 ; AUD:72 (« pour chaque personne ») |
| F5 | Ordre **dans `Person::Cum`** : `PersonCumming := self` → macro `IncrementInt(Sex_OrgasmCounts)` → `Sex_Orgasm := 0.0` → `PlayCumParticle` → `GiveOrgasmReward` → `SetText(CumText)` → `SwitchInteger` → `GI.Cum(ForceEnd = false, NoEnd = true)`. Tout est synchrone. L'incrément de `Sex_OrgasmCounts` n'existe **qu'ici** (accroche H1 d'ORG5 ; 0 occurrence de `Sex_OrgasmCounts` dans GI-P2, Grep). | P-STG:17592-17594 ; P-STG:16121-16125 ; P-STG:17282-17284 ; P-STG:16751-16753 ; P-STG:16107-16110 ; P-STG:15980-15982 ; P-STG:15958-15973 |
| F5b | Les autres appelants de `GI.Cum` dans Person passent aussi `ForceEnd = false` : `Cum` (deux appels, `NoEnd = true`) et `Exhausted` (`NoPregCheck = true`, `NoEnd = false`, `NoShake = true`). Donc la boucle O4c (branche `ForceEnd` vrai) **n'est jamais exécutée lors d'un orgasme réel ni d'un épuisement**. | P-STG:15962, 15970 ; P-STG:16000-16007 ; GI-P2:14554-14558 |
| F6 | **Macro `ForEachLoop`** : nœud existant `MacroInstance_806` sur `SexPersons` : `Exec` ← 4 sources, `Array` ← `VariableGet_15054.SexPersons`, `LoopBody` → `CallFunction_34754.execute` dont `then` est **vide** (corps qui se termine dans une impasse : la boucle passe à l'élément suivant), `Array Element` → `VariableGet_13432.self`, `Completed` → `VariableSet_5686.execute`. type_id **relu sur nœud existant** : `Utilities|Array|ForEachLoop`, broches : entrées `Exec` 0, `Array` 1 ; sorties `LoopBody` 0, `Array Element` 1, `Array Index` 2, `Completed` 3. | GI-P2:7094-7100 ; GI-P2:11216-11220 ; H3gI:34 |
| F7 | Précédents de création de macros par `create_node` avec un type_id en anglais `Utilities|…` : `Utilities|IsValid` → `K2Node_MacroInstance_72` ; `Utilities|FlowControl|WhileLoop` → `MacroInstance_44`. `Utilities|Array|ForEachLoop` lui-même n'a **jamais été créé** par MCP ici (`ForEachLoopWithBreak` était prévu en STG-B1 puis remplacé par `SphereOverlapActors`). | B2PI:31, 124-127 ; H10I:57 ; STG-B1-IMPL.md:167, 219-220 |
| F8 | `PrintString` : type_id **relu en 5.8 et déjà créé dans GI** : `Développement|PrintString` ; broches `execute` 0, `InString` 1, `bPrintToScreen` 2, `bPrintToLog` 3 (défaut true), `then` 0. | H5bC:13-18 |
| F9 | Comparateur `<` : `Utilitaires|Opérateurs|Inférieurà(<)` **créé** en B7a (nœud promotable) et en CAM-B0 (cité par STG-B1) ; se type en reliant `A` d'abord, puis `B` posé par `set_pin_value`. `Supérieuràouégalà(>=)` est **listé** par `find_node_types` (`gal` + contexte) mais **jamais créé**. | B7aI:24, 32, 44 ; STG-B1-IMPL.md:193 |
| F10 | Autres type_id relus : Branche `Utilitaires|ContrôleDeFlux|Branche` (execute 0, Condition 1 ; then 0, else 1) ; IsValid **pur** `Utilitaires|IsValid` (`Object` 0, `ReturnValue` 0) — **pas** la macro `Utilities|IsValid` ; lecteur d'une variable de Person depuis GI `Classe|Person|Obtenir<Var>` (modèle `ObtenirValid`, `self` entrée 0) ; appel d'un événement de Person `Classe|Person|<Nom>` (modèle `MovetoPersonStand`). | H3gI:45-46 ; B2PI:124-127 ; H10G1:47, 114, 168 ; B7aI:21-22, 37-38 |
| F11 | `GiveOrgasmReward` : événement personnalisé de l'EventGraph de Person (sans paramètre) : `OrgasmIrBoost`, puis `ModifyStat mood +20` si `isPlayer`, sinon `attractiontoplayer` (+3 / +6) si le joueur est dans `SexPersons`, rien sinon ; n'appelle aucun nœud de GI. | P-STG:16059-16106 ; P-STG:19074-19077 ; AUD:23 |
| F12 | `SexPersons` : il existe un appel `SortSexPersonsByGender` dans GI : l'ordre des index n'est pas toujours l'ordre de création (ordre exact **non lu**). | GI-P2:10451 |
| F13 | **Précédent exact de la lecture « pénis »** (type_id et chaîne de nœuds à reproduire). Dans **Person** : `VariableGet_14` (`IsMale`) → `BooleanOR.A` ; `VariableGet_15` (`Genital`, Texte) → `CallFunction_884` `Conv_TextToString` → `CallFunction_12` `EqualEqual_StriStri` (`A` ← conversion, `B` = `'Penis'`) → `BooleanOR.B` ; la sortie du OU est l'un des trois termes d'un ET (`CommutativeAssociativeBinaryOperator_1`). Dans **GI** : `GetArrayItem_2` (élément de `SexPersons`) → `VariableGet_84` (`IsMale`) → `Not_PreBool` ; `VariableGet_85` (`Genital`, `self` = l'élément) → `CallFunction_5` `Conv_TextToString` → `CallFunction_1060` `EqualEqual_StriStri` (`B` = `'Penis'`) → ET : c'est la combinaison « non `IsMale` ET pénis », suivie du test de l'étiquette `'Shemale'` (`Array_Contains`). Une variante à comparaison de textes existe aussi dans GI : `EqualEqual_IgnoreCase_TextText` (non retenue : le précédent de la règle « Close to cumming » est la forme chaîne). | P-STG:17340-17359 ; P-STG:17343-17347 ; GI-P2:18904-18931 ; GI-P2:18937-18946 ; GI-P2:14315-14325 |
| F14 | `Math|Booléen|ORBoolean` : type_id **relu et créé** en 5.8 (dans Room, nœud `CommutativeAssociativeBinaryOperator_60`, `A` et `B` reliés ; réponse de `find_node_types` au filtre `ORBoolean` : `XORBoolean`, `ORBoolean`, `NORBoolean` → prendre **exactement** `ORBoolean`). Dans le dump il apparaît sous `KismetMathLibrary::BooleanOR()`. | CAMB2g:38-39, 69, 175 ; P-STG:17343 |
| F15 | `EqualEqual_StriStri` (« Equal, Case Insensitive (String) », titre compact `==`) compare **sans tenir compte de la casse** (`FCString::Stricmp`). `'Penis'` et `'penis'` sont donc équivalents. | UE`Runtime\Engine\Private\KismetStringLibrary.cpp:34-37` ; UE`Runtime\Engine\Classes\Kismet\KismetStringLibrary.h:285-286` |
| F16 | Le jeu **permet** un personnage non `IsMale` avec pénis : le pénis est replacé selon `IsMale` (`MalePenisLocation` si vrai, `FemPenisLocation` sinon) ; GI teste « non `IsMale` ET `Genital == 'Penis'` » puis l'étiquette `'Shemale'` ; Person filtre « FF + `Shemale` » pour « Close to cumming ». La **création** d'un tel personnage au chargen n'est pas lue (dump du chargen absent). | GI-P2:3790-3802, 3806-3807 ; GI-P2:18904-18946 ; P-STG:17376-17396 |
### 1.3 Objectifs mesurables
- **O4a** (inchangé, ORG4S § 2.2) : 2 avertissements `Accessed None … PersonCumming` par clic `Endsex` (ORG4S § 1.1) → **0**. `GI:EventGraph` : N0 → N0 + 3.
- **O4c** (changement de comportement voulu, décisions de l'utilisateur du 2026-10-14) : à `Endsex` (branche `ForceEnd` vrai de `GI::Cum`, **avant** `AfterCumSpeed` / `EndSex`), **chaque** élément de `SexPersons`, **l'un après l'autre** (index 0, 1, …), reçoit `GiveOrgasmReward` **si et seulement si** : (**homme** et `Sex_Orgasm >= 90`) **ou** (**non homme** et `Sex_Orgasm >= 100`), où **homme** = (`IsMale` vrai **OU** `Genital == 'Penis'`) ; un marqueur de trace par bonus donné (`ORG4 bonus Endsex homme` / `… femme` ; `homme` = groupe du seuil 90 au sens de la règle, `femme` = groupe du seuil 100) ; **aucun** `Person::Cum` ; `Sex_OrgasmCounts` inchangé ; une personne non éligible ou invalide ne bloque pas les suivantes. `GI:EventGraph` : + **17** nœuds.
- **Total** (O4a + O4c) : `GI:EventGraph` **N0 + 20 = 6 273** ; 2 coupures ; 32 liens ; 8 valeurs posées ; MD5 de Person et de SexAction inchangés ; `Sex_OrgasmCounts` jamais écrit par GI (V5).
## 2. Fichiers touchés, ordre
Un seul fichier : `Content\BPs\GI.uasset`, graphe `EventGraph` (événements `AfterCumSpeed` pour O4a, `Cum` branche `ForceEnd` pour O4c). Ni Person, ni SexAction, ni PC, ni C++, ni scènes, ni modules. **Ordre** : P0 à P7 → O4a → O4c → `compile_blueprint` → `save_assets` unique → fermeture de l'éditeur. O4a et O4c dans **une seule session MCP, un seul instantané, un seul `save_assets`**. Aucun nœud commun aux deux (O4a : `CustomEvent_702`, `VariableSet_9760`, `CallFunction_960`, `VariableGet_720` ; O4c : `IfThenElse_875`, `CallFunction_11423`, `VariableGet_3498`).
### 2.0 Préalables (identiques à ORG4S § 2.0, adaptés)
- **P0 (bloquant pour O4c)** : dump du gestionnaire de clic de `SexAction`, é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"` (demandé à Big Boss, non attendu ici). **Attendu** : un appel `GI_C::Cum` avec `ForceEnd = 'true'` sur le chemin de la comparaison avec `'Endsex'`, aucun appel direct de `EndSex`. **Écart** : arrêt, rapport (O4c serait sans effet ; V5 passerait, V6-S1 échouerait).
- **P1** : MD5 de GI à l'entrée (attendu `e64b5b37…`) ; refaire le dump `-BP=GI -Fn=EventGraph -Pins -Exec` (en-tête attendu `=== GI :: EventGraph (6253 noeuds) ===`) ; **relever dans ce dump** les comptes de référence pour V5, avec le même Grep avant et après (le fichier contient deux blocs, § État relevé) : `macro 'ForEachLoop'` (GI-P2 : **79** lignes, Grep `macro 'ForEachLoop'` → `79`, baseline à refaire sur le dump P1), `PrintString`, `GiveOrgasmReward` (attendu 0), `variable 'IsMale'`, `variable 'Genital'` (GI-P2 : 4 lignes aux l. 14315, 18920, 19919, 20792 dans la liste Grep limitée à 20 lignes ; recompter), `Conv_TextToString`, `EqualEqual_StriStri`, `BooleanOR`, `variable 'Sex_Orgasm'` (GI-P2 : 0).
- **P2** : MD5 relevé juste avant l'IMPL = valeur de repli.
- **P3** : gel annoncé à **toutes** les sessions (`lp-mcp` § 1 règle 7) ; `.\Tools\Snapshot.ps1 -Lot STE-ORG4` ; é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 ; tout écart : arrêt) : `CustomEvent_4245`, `IfThenElse_172`, `IfThenElse_98`, `IfThenElse_875`, `IfThenElse_876`, `CallFunction_11423`, `VariableGet_3498`, `GetArrayItem_1037`, `MacroInstance_18`, `MacroInstance_806` (modèle d'indices de la macro) ; puis ceux d'O4a (ORG4S § 2.0 P4 : `CustomEvent_702`, `VariableSet_9760`, `CallFunction_960`, `VariableGet_720`, `VariableGet_721`, `VariableGet_722`) ; **modèles de la chaîne `Genital`** pour les indices de broches : `VariableGet_85`, `CallFunction_5`, `CallFunction_1060` (GI-P2:18920-18931) et, pour le OU, le nœud Room `CommutativeAssociativeBinaryOperator_60` (CAMB2g:69) si la lecture de Room est permise (sinon relever les indices sur le nœud créé). **Liens attendus** : `IfThenElse_875.then` → `CallFunction_11423.execute` seul ; `CallFunction_11423.execute` ← `IfThenElse_875.then`, `CallFunction_32955.then`, `IfThenElse_189.then` (GI-P2:10906) ; `IfThenElse_875.else` → `MacroInstance_18.exec` (14558) ; `VariableGet_3498.SexPersons` → `GetArrayItem_1037.Array` seul (10879-10883) ; `MacroInstance_806` : broches `Exec` 0, `Array` 1, `LoopBody` 0, `Array Element` 1, `Array Index` 2, `Completed` 3 (à confirmer sur le nœud créé) ; `VariableGet_85.self` ← `GetArrayItem_2.Output`, `CallFunction_1060.B` = `Penis`.
- **P5 (type_id)** : avant chaque `create_node`, `find_node_types {graph:{refPath:"/Game/BPs/GI.GI:EventGraph"}, type_id_filter:<filtre du § 2.1>, context_pins:[]}` ; le type_id attendu doit figurer **exactement** dans la réponse (sinon arrêt) ; après création, `get_node_infos` du nœud (indices). **Pas de type_id improvisé.**
- **P6** : P0 lu et conforme ; décisions de l'utilisateur reçues (section « Décisions » : Q1 gardé, Q2 = `IsMale` OU `Genital`, Q3 `>=`, Q4 oui, Q5 deux libellés) ; Q-ORG4c-6 (UE-GO) donné.
- **P7** (lecture, sans écriture) : `find_node_types` filtre `GiveOrgasmReward` → `Classe|Person|GiveOrgasmReward` ; filtre `IsMale` → l'entrée `Classe|Person|ObtenirIsMale` (parmi d'éventuelles autres : prendre celle de **Person**) ; filtre `Orgasm` → l'entrée `Classe|Person|ObtenirSexOrgasm` (le tiret bas disparaît : règle reprise de ORG4S § 2.1, exemple `ObtenirVolBGA`) ; filtre `Genital` → l'entrée `Classe|Person|ObtenirGenital` (de **Person**). Person MD5 `8668a47c…` à l'entrée, sinon arrêt. Aucun enregistrement de Person.
### 2.1 Conventions et table des type_id
| Rôle | type_id | État | Filtre `find_node_types` |
|---|---|---|---|
| Boucle | `Utilities|Array|ForEachLoop` | **relu sur nœud existant** (H3gI:34) ; **création jamais faite** → à relever | `ForEachLoop` : prendre l'entrée **exacte** `Utilities|Array|ForEachLoop` (comme `Utilities|IsValid`, elle peut être rendue deux fois) ; **écarter** `ForEachLoopwithBreak` (H10G2:146) et toute variante `Map` / `Set` ; absente : arrêt |
| Branche | `Utilitaires|ContrôleDeFlux|Branche` | relu et créé | `ContrôleDeFlux|Branche` |
| IsValid pur | `Utilitaires|IsValid` | relu et créé | `IsValid` (5 réponses : prendre exactement `Utilitaires|IsValid`, pas `Utilities|IsValid`) |
| Lecteur `IsMale` | `Classe|Person|ObtenirIsMale` | **attendu**, jamais créé | `IsMale` |
| Lecteur `Genital` | `Classe|Person|ObtenirGenital` | **attendu**, jamais créé ; la variable est un **Texte** (F13) | `Genital` |
| Conversion Texte vers chaîne | fonction `Conv_TextToString` (KismetTextLibrary) ; **type_id jamais créé, à relever** | précédent de nœud : P-STG:17351-17354, GI-P2:18923-18926 | `ToString` puis `Texte` / `Text`, **avec `context_pins` = sortie `Genital` de O4c-N** (créer O4c-N avant) ; le nœud créé doit porter `Conv_TextToString` (broche `InText` Texte, `ReturnValue` chaîne) ; sinon arrêt |
| Égalité de chaînes | fonction `EqualEqual_StriStri` (« Equal, Case Insensitive (String) », titre compact `==`, F15) ; **type_id jamais créé, à relever** | précédent de nœud : P-STG:17355-17359, GI-P2:18927-18931 | `Insensitive` puis `casse` puis `==`, **avec `context_pins` = sortie de O4c-T** ; l'entrée `Utilitaires|Opérateurs|Égalà(==)` (promotable, listée en B7aI:24, jamais créée) n'est acceptable que si, après liaison de `A`, `get_node_infos` montre des broches de type chaîne ; le dump V5 doit afficher `KismetStringLibrary::EqualEqual_StriStri()` ; sinon arrêt |
| OU booléen | `Math|Booléen|ORBoolean` | relu **et créé** en 5.8 (F14) | `ORBoolean` : 3 réponses (`XORBoolean`, `ORBoolean`, `NORBoolean`) → prendre `ORBoolean` |
| Lecteur `Sex_Orgasm` | `Classe|Person|ObtenirSexOrgasm` | **attendu**, jamais créé | `Orgasm` |
| Comparateur `<` | `Utilitaires|Opérateurs|Inférieurà(<)` | relu et créé (promotable) | `Opérateurs|` avec contexte (B7aI:25) ou `Inférieur` |
| Marqueur | `Développement|PrintString` | relu et créé dans GI | `PrintString` (écarter les deux entrées PCG) |
| Bonus | `Classe|Person|GiveOrgasmReward` | **attendu** (P7), jamais créé | `GiveOrgasmReward` |
- **Pourquoi `<` + `else`** : « `Sex_Orgasm >= seuil` » (décision Q3) = « non (`Sex_Orgasm < seuil`) » ; le comparateur `<` est le seul déjà créé ; le chemin « éligible » est la sortie **`else`** de la Branche. `>=` listé mais jamais créé reste un repli (même sémantique, branches inversées).
- **Cascades de branches** (`lp-mcp` § 1 règle 4 : pas de Select, AND, OR purs) **sauf une exception décidée** : le OU `O4c-O` (consigne de l'orchestrateur du 2026-10-14). Il est sûr ici : ses deux opérandes sont des **lectures pures** (`IsMale`, comparaison de `Genital`) sur l'élément que `O4c-B0` (garde `IsValid`) a déjà validé ; aucune lecture sur objet nul, donc la règle 4 (« tout est évalué ») ne crée pas d'`Accessed None` (R-ORG4c-11). **Pas de `Person::Cum` appelé depuis GI** (ORG4S § 2.3, R-ORG4-5). `delete_node` interdit. Positions libres. Outils Epic seulement, un appel MCP par message.
- **Ordre des liens et types génériques** : les broches `Array` et `Array Element` de la macro sont génériques et prennent le type de l'élément (Person) au lien 2 ; faire les liens 1 à 3 d'abord, relire le type de `Array Element` (référence Person) **avant** le lien 5 ; de même, `O4c-C1.A` / `O4c-C2.A` avant leur `B`, et `O4c-E.A` avant `O4c-E.B` (la valeur `Penis` se pose une fois `A` typé chaîne).
- Compilation et enregistrement : `compile_blueprint {blueprint:{refPath:"/Game/BPs/GI.GI"}, warnings_as_errors:true}` → `null`, journal de l'éditeur lu ; **puis** `save_assets {asset_paths:["/Game/BPs/GI"]}` ; `hyper_blueprint_debug_inspect` absent (mémoire du projet) : repli = compilation stricte + journal ; éditeur fermé, `.\Tools\UeState.ps1` = 0, MD5 relevé.
### 2.2 Garde `PersonCumming` — O4a
**Reprise telle quelle de ORG4S § 2.2** (nœuds O4a-V `Utilitaires|IsValid`, O4a-B Branche, O4a-S `Définir Rate` ; 1 coupure `CustomEvent_702.then` / `VariableSet_9760.execute` ; 6 liens ; `Rate` = `0.25`). **Comptes O4a** : 3 nœuds ; 1 coupure ; 6 liens ; 1 valeur. Elle est exécutée **avant** O4c (ordre sans importance technique : nœuds disjoints).
### 2.3 Bonus à `Endsex` pour chaque participant — O4c (événement `Cum`, branche `ForceEnd`)
**Schéma** (L = boucle ; les impasses sont voulues et marquées ⊘) :
```
IfThenElse_875.then → L.Exec
L.Array ← VariableGet_3498.SexPersons
L.LoopBody → B0 (IsValid de l'élément)
B0.else ⊘ (élément invalide : itération suivante)
B0.then → B1 Condition de B1 = O = ( M : IsMale de l'élément ) OU ( E : Conv(Genital de l'élément) == 'Penis' )
B1.then (homme au sens de la règle) → B2 (Sex_Orgasm < 90 ?)
B2.then ⊘ (jauge < 90 : pas de bonus, itération suivante)
B2.else → Ph (marqueur « homme ») → R
B1.else (non homme) → B3 (Sex_Orgasm < 100 ?)
B3.then ⊘ (jauge < 100 : pas de bonus)
B3.else → Pf (marqueur « femme ») → R
R = GiveOrgasmReward(élément) ; R.then ⊘ (itération suivante)
L.Completed → CallFunction_11423.execute (AfterCumSpeed, suite existante)
Chaîne de données de la condition : L.Array Element → M.self ; L.Array Element → N.self (Genital) → T (Texte vers chaîne) → E (== 'Penis') ; M et E → O → B1.Condition
```
**Nœuds créés** (17 ; ordre de création conseillé : L, V, B0, M, N, T, E, O, B1, G, C1, C2, B2, B3, Ph, Pf, R ; N avant T, T avant E à cause des `context_pins`) :
| ID | Nœud | type_id (P5, § 2.1) | Broches (à relever par `get_node_infos`) |
|---|---|---|---|
| O4c-L | ForEachLoop | `Utilities|Array|ForEachLoop` | in `Exec` 0, `Array` 1 ; out `LoopBody` 0, `Array Element` 1, `Array Index` 2, `Completed` 3 (indices de H3gI:34, à confirmer) |
| O4c-V | IsValid (pur) | `Utilitaires|IsValid` | `Object` 0 ; `ReturnValue` 0 |
| O4c-B0 | Branche (garde) | `Utilitaires|ContrôleDeFlux|Branche` | execute 0, Condition 1 ; then 0, else 1 |
| O4c-M | Lecteur `IsMale` | `Classe|Person|ObtenirIsMale` | `self` 0 ; sortie `IsMale` 0 (booléen) |
| O4c-N | Lecteur `Genital` | `Classe|Person|ObtenirGenital` | `self` 0 ; sortie `Genital` 0 (Texte) |
| O4c-T | Conversion Texte vers chaîne | `Conv_TextToString` (type_id à relever, § 2.1) | `InText` 0 ; `ReturnValue` 0 (chaîne) |
| O4c-E | Égalité de chaînes sans casse | `EqualEqual_StriStri` (type_id à relever, § 2.1) | `A` 0, `B` 1 ; `ReturnValue` 0 |
| O4c-O | OU booléen | `Math|Booléen|ORBoolean` | `A` 0, `B` 1 ; `ReturnValue` 0 (nœud à broches ajoutables : ne pas en ajouter) |
| O4c-B1 | Branche (sexe) | `Utilitaires|ContrôleDeFlux|Branche` | idem B0 |
| O4c-G | Lecteur `Sex_Orgasm` | `Classe|Person|ObtenirSexOrgasm` | `self` 0 ; sortie `Sex_Orgasm` 0 (double) |
| O4c-C1 | Comparateur `<` (seuil homme) | `Utilitaires|Opérateurs|Inférieurà(<)` | `A` 0, `B` 1 ; `ReturnValue` 0 |
| O4c-C2 | Comparateur `<` (seuil femme) | idem | idem |
| O4c-B2 | Branche (homme) | Branche | idem |
| O4c-B3 | Branche (non homme) | Branche | idem |
| O4c-Ph | PrintString « homme » | `Développement|PrintString` | execute 0, `InString` 1, `bPrintToScreen` 2, `bPrintToLog` 3 ; then 0 |
| O4c-Pf | PrintString « femme » | idem | idem |
| O4c-R | Appel `Person_C::GiveOrgasmReward` | `Classe|Person|GiveOrgasmReward` | execute 0, `self` 1 ; then 0 (à relever) |
**Coupure** (1) : `break_pins` `IfThenElse_875.then` (sortie 0) / `CallFunction_11423.execute` (entrée 0).
**Liens** (26), un appel `connect_pins` par message, dans cet ordre (relier `O4c-G.Sex_Orgasm` à `O4c-C1.A` et à `O4c-C2.A` **avant** de poser les `B` ; relier `O4c-T.ReturnValue` à `O4c-E.A` **avant** de poser `O4c-E.B`) :
1. `IfThenElse_875.then` (0) → `O4c-L.Exec` (0)
2. `VariableGet_3498.SexPersons` → `O4c-L.Array` (1) (le lien vers `GetArrayItem_1037.Array` reste)
3. `O4c-L.Completed` (3) → `CallFunction_11423.execute` (0)
4. `O4c-L.LoopBody` (0) → `O4c-B0.execute` (0)
5. `O4c-L.Array Element` (1) → `O4c-V.Object` (0)
6. `O4c-V.ReturnValue` (0) → `O4c-B0.Condition` (1)
7. `O4c-B0.then` (0) → `O4c-B1.execute` (0)
8. `O4c-L.Array Element` → `O4c-M.self` (0)
9. `O4c-M.IsMale` (0) → `O4c-O.A` (0)
10. `O4c-L.Array Element` → `O4c-N.self` (0)
11. `O4c-N.Genital` (0) → `O4c-T.InText` (0)
12. `O4c-T.ReturnValue` (0) → `O4c-E.A` (0)
13. `O4c-E.ReturnValue` (0) → `O4c-O.B` (1)
14. `O4c-O.ReturnValue` (0) → `O4c-B1.Condition` (1)
15. `O4c-B1.then` (0) → `O4c-B2.execute` (0)
16. `O4c-B1.else` (1) → `O4c-B3.execute` (0)
17. `O4c-L.Array Element` → `O4c-G.self` (0)
18. `O4c-G.Sex_Orgasm` (0) → `O4c-C1.A` (0)
19. `O4c-G.Sex_Orgasm` (0) → `O4c-C2.A` (0)
20. `O4c-C1.ReturnValue` (0) → `O4c-B2.Condition` (1)
21. `O4c-C2.ReturnValue` (0) → `O4c-B3.Condition` (1)
22. `O4c-B2.else` (1) → `O4c-Ph.execute` (0)
23. `O4c-B3.else` (1) → `O4c-Pf.execute` (0)
24. `O4c-Ph.then` (0) → `O4c-R.execute` (0)
25. `O4c-Pf.then` (0) → `O4c-R.execute` (0)
26. `O4c-L.Array Element` → `O4c-R.self` (1)
**Valeurs** (7, `set_pin_value`, relire avant et après) : `O4c-E.B` = `Penis` (après le lien 12) ; `O4c-C1.B` = `90.0` (après le lien 18) ; `O4c-C2.B` = `100.0` (après le lien 19) ; `O4c-Ph.InString` = `ORG4 bonus Endsex homme` ; `O4c-Ph.bPrintToScreen` = `false` ; `O4c-Pf.InString` = `ORG4 bonus Endsex femme` ; `O4c-Pf.bPrintToScreen` = `false` (`bPrintToLog` reste vrai).
**Relecture** (`get_node_infos` des 17 nœuds + des 3 existants touchés) :
- `IfThenElse_875.then` → `O4c-L.Exec` **seul** ; `IfThenElse_875.else` → `MacroInstance_18.exec` **inchangé** ;
- `CallFunction_11423.execute` ← **3 sources** : `O4c-L.Completed`, `CallFunction_32955.then`, `IfThenElse_189.then` (même nombre qu'avant : `IfThenElse_875.then` est remplacé par `O4c-L.Completed`) ;
- `VariableGet_3498.SexPersons` → 2 cibles (`GetArrayItem_1037.Array`, `O4c-L.Array`) ;
- `O4c-L.Array Element` → **5 cibles** (`O4c-V.Object`, `O4c-M.self`, `O4c-N.self`, `O4c-G.self`, `O4c-R.self`) ; `O4c-G.Sex_Orgasm` → 2 cibles ; `O4c-R.execute` ← 2 sources (`Ph.then`, `Pf.then`) ;
- condition du sexe : `O4c-O.A` ← `O4c-M.IsMale` ; `O4c-O.B` ← `O4c-E.ReturnValue` ; `O4c-E.A` ← `O4c-T.ReturnValue` ; `O4c-E.B` = `Penis` ; `O4c-T.InText` ← `O4c-N.Genital` ; **`O4c-B1.Condition` ← `O4c-O.ReturnValue`** (et non plus `O4c-M` directement) ;
- les **4 Branches** (B0, B1, B2, B3) ont leur `Condition` reliée (sinon `true` par défaut) ;
- **impasses vérifiées vides** : `O4c-B0.else`, `O4c-B2.then`, `O4c-B3.then`, `O4c-R.then` (aucun lien : un lien accidentel casserait le « passer au suivant ») ; `O4c-L.Array Index` sans lien ;
- `O4c-C1` et `O4c-C2` typés double (`A` et `B` « Float (double-précision) », comme en B7a) ; `B` = 90 / 100 ; `O4c-E` typé chaîne (`A` et `B`).
**Comptes O4c** : 17 nœuds ; 1 coupure ; 26 liens ; 7 valeurs.
**Variantes chiffrées** (écartées par les décisions du 2026-10-14, gardées pour mémoire ; recalculées à partir de la version à `Genital`) :
| Variante | Effet | Nœuds O4c | Liens O4c | `GI:EventGraph` (avec O4a) |
|---|---|---|---|---|
| **Retenue** | garde + `IsMale` OU `Genital == 'Penis'` + deux seuils | **17** | **26** | **6 273** |
| Sans garde `IsValid` (Q4 = non, écartée) | retirer O4c-V et O4c-B0 ; `L.LoopBody` → `B1.execute` | 15 | 23 | 6 271 |
| `IsMale` seul (Q2 = a, écartée) | retirer O4c-N, T, E, O ; `M.IsMale` → `B1.Condition` | 13 | 21 | 6 269 |
| Hommes seuls (Q1 = b, écartée) | retirer O4c-C2, O4c-B3, O4c-Pf ; `B1.else` ⊘ | 14 | 21 | 6 270 |
| Repli sans OU (si `ORBoolean` non créable) | retirer O4c-O ; ajouter une Branche `Bg` : `M.IsMale` → `B1.Condition` ; `B1.else` → `Bg.execute` (Condition ← `E.ReturnValue`) ; `Bg.then` → `B2.execute` ; `Bg.else` → `B3.execute` ; `B1.then` → `B2.execute` | 17 | 27 | 6 273 |
### 2.4 Comptes et résultat attendu de l'IMPL
| | O4a | O4c | Total |
|---|---|---|---|
| Nœuds créés | 3 | 17 | **20** |
| `GI:EventGraph` (N0 = 6 253) | N0 + 3 | N0 + 17 | **6 273** |
| Coupures | 1 | 1 | **2** |
| Liens créés | 6 | 26 | **32** |
| `set_pin_value` | 1 | 7 | **8** |
Gestes d'écriture attendus : 20 `create_node` + 2 `break_pins` + 32 `connect_pins` + 8 `set_pin_value` = **62**, plus ≈ 12 lectures `find_node_types` et ≈ 8 `get_node_infos` : à budgéter pour l'IMPL (`sk-protocol` § 8, opération qui ne doit pas être coupée).
Inchangés (VAL) : toutes les autres fonctions de GI ; `isSameAs` 11, `GetVariable` 53, `CallFunctionReturnBool` 594, `Action:EventGraph` 363 (repris de ORG4S § 2.4 / H3gV:34, non relus aujourd'hui).
### 2.5 Comportement avant / après (cas nommés)
« Homme » = `IsMale` vrai OU `Genital == 'Penis'` (sans casse). « Non homme » = `IsMale` faux ET `Genital` différent de `'Penis'` (autre valeur, texte vide compris).
| Cas | Avant | Après |
|---|---|---|
| `Endsex`, homme (`IsMale` vrai) avec `Sex_Orgasm >= 90` | scène terminée, aucun bonus | **bonus** (`GiveOrgasmReward`) puis fin identique ; marqueur `… homme` ×1 |
| `Endsex`, **personne non `IsMale` avec `Genital == 'Penis'`** et `Sex_Orgasm >= 90` | fin, aucun bonus | **bonus** ; marqueur `… homme` ×1 (V6-S6) |
| `Endsex`, homme (au sens de la règle) avec jauge < 90 | fin | fin identique ; 0 bonus ; 0 marqueur |
| `Endsex`, non homme avec jauge `>= 100` | fin | bonus ; marqueur `… femme` — **cas inatteignable en pratique** (F4) ; branche écrite par fidélité à la décision (gardée) |
| `Endsex`, non homme avec jauge < 100 (cas réel de toute femme sans pénis) | fin | fin identique ; 0 bonus ; 0 marqueur |
| Ordre | — | index 0, puis 1, … de `SexPersons` (ordre du tableau, éventuellement trié par `SortSexPersonsByGender`, F12) ; `GiveOrgasmReward` est synchrone, un participant après l'autre |
| Un participant non éligible ou invalide | — | **ne bloque pas** les suivants : sa branche s'arrête dans une impasse, la boucle passe à l'élément suivant (F6) |
| `SexPersons` vide | (cas non rencontré) | `Completed` aussitôt → `AfterCumSpeed` : chemin d'aujourd'hui |
| Double bonus avec `Finish` / orgasme à 100 | — | **impossible** : (1) ces chemins appellent `GI.Cum` avec `ForceEnd = false` (F5b) et n'entrent pas dans la boucle ; (2) `Person::Cum` remet `Sex_Orgasm` à 0 avant son propre `GiveOrgasmReward` (F5), donc la personne n'est pas éligible à un `Endsex` suivant |
| Pas d'effet d'orgasme | — | pas de `Person::Cum` : pas de remise à 0 de la jauge, pas d'incrément de `Sex_OrgasmCounts` (F5 : l'incrément n'existe que dans `Person::Cum`), pas de particule ni de texte `CumText`, pas de secousse. **Note pour ORG5 H1** : le sondage du compteur ne verra pas ce bonus (R7 d'ORG5S, accepté pour l'alpha, ORG5S:294) |
| Créatures (`IsMale` vrai, ou `Genital` de la créature : non lu) | — | traitées comme un homme si `IsMale` vrai ou `Genital == 'Penis'` ; `GiveOrgasmReward` leur est appliqué comme à un orgasme réel (même événement) ; effet de `ModifyStat` sur une créature non lu (estimé) |
| Jauge restée ≥ seuil après `Endsex` | — | pas de farm : la scène est défaite et `UpdateSexLikes` remet `Sex_Orgasm` à 0 au démarrage de la scène suivante (P-STG:15804-15812 ; ORG4S § 2.5) |
| `PersonCumming` `None` à `Endsex` | 2 avertissements | 0 (O4a) |
### 2.6 Règle commune ORG4 / ORG5 (Big Boss, 2026-10-14, ORG4S:265-269) : comment O4c la tient
1. **Orgasme réel** (`Person::Cum`) : `GiveOrgasmReward` **1×** (chemin existant, F5) ; ORG5 **1×** déclenché par l'incrément de `Sex_OrgasmCounts` (accroche H1, ORG5S:298). O4c ne s'exécute pas sur ce chemin (`ForceEnd = false`, F5b) : **0× de plus**.
2. **`Endsex`** : `GiveOrgasmReward` **1× par participant éligible**, **sans** `Person::Cum` ; `Sex_OrgasmCounts` **inchangé** (aucun nœud de GI ne l'écrit : 0 occurrence dans GI-P2, et O4c ne crée aucun nœud qui le nomme ; V5 le reverifie par Grep sur le dump d'après) donc **0 récompense ORG5** à `Endsex`.
3. **Participant qui vient de jouir** : jauge à 0 (F5), donc non éligible à un `Endsex` suivant : pas de second bonus de base pour le même orgasme.
4. **Contrôle V6** : voir § 7 (S2, S4 et la dernière ligne du tableau) ; limite : le bonus de base d'un orgasme **réel** ne laisse **aucune ligne de journal** (Person non modifié, `ModifyStat` sans trace) : la règle « 1 marqueur de base par orgasme » n'est observable en journal que pour la voie `Endsex` (marqueurs O4c) ; pour la voie orgasme réel, la preuve est l'absence de marqueur O4c et le texte à l'écran (Q-ORG4c-5, décidée : pas de marqueur à l'orgasme réel).
5. **Condition de validité** : toute IMPL d'ORG5 qui déplacerait son accroche vers `GiveOrgasmReward` (au lieu de l'incrément de `Sex_OrgasmCounts`) casserait le point 2 : à relire dans ORG5 avant l'IMPL (ORG5S:298-300).
## 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, contrôler le MD5, rapporter. Aucun correctif improvisé.
- Après enregistrement, lien relu différent, `type_id` introuvable (P5), nœud inattendu, impasse reliée par erreur, 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 conservés) ; aucune autre écriture de GI intercalée.
- **Repli de conception** : (i) P0 contraire, ou `Utilities|Array|ForEachLoop` introuvable en création → **O4a seul** (3 nœuds, `GI:EventGraph` N0 + 3) et retour à l'orchestrateur ; (ii) `Classe|Person|ObtenirIsMale`, `…ObtenirGenital` ou `…ObtenirSexOrgasm` introuvable → arrêt (pas de repli par `ObjectTools`) ; (iii) le marqueur gêne → l'omettre (retirable, ignoré en Shipping), mais Q-ORG4-3 = oui impose son maintien ; (iv) `Inférieurà(<)` non créable ici → `Supérieuràouégalà(>=)` avec Branches inversées, sinon arrêt ; (v) `ORBoolean` non créable → cascade de deux Branches (variante « Repli sans OU », § 2.3) ; (vi) conversion Texte vers chaîne ou égalité de chaînes introuvables → comparaison de textes `EqualEqual_IgnoreCase_TextText` (précédent GI-P2:14321-14325, `B` à poser comme Texte) **seulement sur décision de l'orchestrateur** (nœud différent du précédent de Person), sinon arrêt.
- Après commit (gardien) : `git revert` du commit du ticket. **Couplage** : `GI.uasset` est un binaire unique qui porte G16 et B7-a (R-ORG4-2 de ORG4S).
## 4. Risques R#, questions Q#
- **R-ORG4c-1** : `ForceEnd = true` de l'appel `GI.Cum` de `SexAction` **déduit**, non lu (ORG4S R-ORG4-1) → P0 bloquant ; V5 passerait même si faux, seul V6-S1 le révèle.
- **R-ORG4c-2** : la branche « non homme » (seuil 100) est **sans effet réel** (F4, estimé fort) ; V6 ne peut pas la rejouer ; sa justesse se vérifie en V5 (statique) seulement. Q-ORG4c-1 (gardée).
- **R-ORG4c-3** : type_id jamais créés ici (sept, voir l'Annonce) ; indices de la macro repris d'un nœud existant (H3gI:34), à confirmer sur le nœud créé ; type générique de `Array Element` à relire après le lien 2 (§ 2.1) ; conversion et égalité de chaînes à relever **avec contexte** (§ 2.1).
- **R-ORG4c-4** : le comportement « impasse dans le corps = élément suivant » est **établi par un précédent du même graphe** (GI-P2:7097, 11216-11218) mais le code de la macro n'est pas lu dans le moteur (§ 6). Si l'impasse arrêtait la boucle, V6-S5 (personne non éligible en index 0) le révélerait.
- **R-ORG4c-5** : deux `ModifyStat` affichés (`NoDisplay` faux, P-STG:16074-16087) à l'image même où `EndSex` défait la scène : textes éventuellement masqués ; l'effet sur la stat existe (ORG4S R-ORG4-4). Avec deux participants éligibles, deux textes dans la même image.
- **R-ORG4c-6** : `GI.uasset` partagé : G16, B7-a non commités dans le même binaire (ORG4S R-ORG4-2).
- **R-ORG4c-7** : tableau modifié pendant l'itération : `GiveOrgasmReward` n'appelle aucun nœud de GI (F11), donc ne touche pas `SexPersons` (estimé) ; la relecture de la longueur par la macro n'est pas lue (§ 6) : incertain, sans conséquence attendue.
- **R-ORG4c-8** : dumps périmés : PC (` M` depuis ORG4S) et Person (dump 14:08, dernière sauvegarde 17:42, ORG4S R-ORG4-8) : P7 et V6 couvrent la chaîne `GiveOrgasmReward`.
- **R-ORG4c-9** : articulation ORG5 : voir § 2.6 point 5 et R7 d'ORG5S ; si ORG5 ajoute une grille à `GiveOrgasmReward` (ORG4S R-ORG4-6), elle s'ouvrirait à l'image de la fin de scène, une fois par participant éligible.
- **R-ORG4c-10** : deux libellés de marqueur (`homme`, `femme`) au lieu du libellé unique de Q-ORG4-3 ; le préfixe commun `ORG4 bonus Endsex` est conservé : le motif de V6 d'ORG4S reste valable. **`homme` désigne le groupe du seuil 90 (`IsMale` OU pénis), pas le sexe d'état civil** : une personne non `IsMale` à pénis écrit un marqueur `homme` (V6-S6).
- **R-ORG4c-11** : exception à `lp-mcp` § 1 règle 4 (OU pur `O4c-O`) : sûre parce que `O4c-B0` précède et que les deux opérandes sont des lectures pures sur l'élément validé ; si `O4c-B0` était retirée (variante écartée), la règle 4 s'appliquerait de nouveau (lectures `IsMale` et `Genital` sur un élément possiblement nul). Repli sans OU prévu (§ 2.3, § 3 v).
- **R-ORG4c-12** : `Genital` est un Texte relu sans casse ; toute autre valeur que `'Penis'` (autre mot, texte localisé, vide) vaut « non homme » : même comportement que « Close to cumming » (F2, F15) ; la valeur réelle de `Genital` pour les créatures et pour les personnages importés d'un mod n'est pas lue.
**Décisions reçues (2026-10-14) et questions restantes**
- **Q-ORG4c-1 — seuil « femme = 100 »** : **décidé : gardé tel quel** (branche sans effet en pratique, F4, acceptée). Options écartées : hommes seuls (3 nœuds de moins), autre seuil.
- **Q-ORG4c-2 — définition de « homme »** : **décidé : `IsMale` OU `Genital == 'Penis'`**, la règle de « Close to cumming » (F2, F13). Intégrée aux § 2.3 à 2.5 et 7 (+4 nœuds : `Genital`, conversion, égalité, OU). Conséquence assumée : une personne non `IsMale` à pénis suit le seuil 90 ; une femme sans pénis suit le seuil 100 (donc jamais de bonus à `Endsex`, F4).
- **Q-ORG4c-3 — « dépasse »** : **décidé : `>= 90` et `>= 100`**, réalisés par `<` + sortie `else` (§ 2.1).
- **Q-ORG4c-4 — garde `IsValid` par élément** : **décidé : oui** (O4c-V, O4c-B0 ; `lp-mcp` § 1 règle 4 réserve normalement `IsValid` aux cas où « vide » est normal, la garde est ici prudentielle et sert aussi la sûreté du OU, R-ORG4c-11).
- **Q-ORG4c-5 — observabilité** : **décidé : deux libellés `homme` / `femme`, pas de marqueur à l'orgasme réel** (Person non modifié) ; la preuve du bonus de base d'un orgasme réel reste le texte à l'écran.
- **Q-ORG4c-6 (orchestrateur)** — UE-GO pour P0 (dump de `SexAction`), puis pour l'IMPL ; gel annoncé ; ticket du gardien (R-ORG4c-6) ; budget d'IMPL ≈ 62 écritures + lectures (§ 2.4). **Reste ouverte.**
- **Q-ORG4c-7 (utilisateur, nouvelle, facultative)** — existe-t-il, au chargen, un personnage non `IsMale` avec `Genital = 'Penis'` rejouable en V6-S6 (F16 : le jeu le prévoit, sa création n'est pas lue) ? Sinon S6 est « non rejoué » et la preuve est statique (V5).
## 5. Interdits
- Aucune modification de Person (aucun `save_assets` de Person), SexAction, PC, `GetVariable`, `CallFunctionReturnBool`, `isSameAs`, `Action`, C++, 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** ; **aucune écriture de `Sex_Orgasm`, `Sex_OrgasmCounts`, `Genital`, `IsMale` ni `PersonCumming` par O4c** ; aucun `FunctionResult` créé ; pas de `delete_node` ; pas de AND / Select purs, ni d'OR pur **hors `O4c-O`** (exception décidée, R-ORG4c-11) ; pas de `type_id` non relu (P5) ; pas d'écriture HyperAIStudio (`lp-mcp` § 1 règle 1) ; outils Epic seulement.
- Aucun lien sur les impasses `O4c-B0.else`, `O4c-B2.then`, `O4c-B3.then`, `O4c-R.then`.
- Pas d'IMPL sans P0 conforme, sans P1 à P7, ni 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(const UObject* WorldContextObject, const FString& InString, bool bPrintToScreen = true, bool bPrintToLog = true, FLinearColor TextColor, float Duration = 2.f, const FName Key)` est `DevelopmentOnly` : `UE`Runtime\Engine\Classes\Kismet\KismetSystemLibrary.h:565-566 (le marqueur est ignoré en Shipping, joué en Development) ; les paramètres de ce fichier correspondent aux broches relevées en H5bC:17-18.
- `UKismetStringLibrary::EqualEqual_StriStri(const FString& A, const FString& B)` rend `FCString::Stricmp(*A, *B) == 0` (**insensible à la casse**) : `UE`Runtime\Engine\Private\KismetStringLibrary.cpp:34-37` ; déclaration `meta=(DisplayName = "Equal, Case Insensitive (String)", CompactNodeTitle = "==")`, catégorie `Utilities|String` : `UE`Runtime\Engine\Classes\Kismet\KismetStringLibrary.h:285-286`.
**Non lu** (donc estimé, pas établi) :
- Le code de la macro `ForEachLoop` (asset de macros du moteur, binaire) : « un corps qui s'arrête dans une impasse passe à l'élément suivant » n'est établi que par l'usage du graphe de GI (GI-P2:7097, 11216-11218) ; « la longueur du tableau est relue à chaque tour » non lu.
- `Less_DoubleDouble` / `FClamp` : seules les formes de nœuds des dumps sont lues (F3). `Conv_TextToString` (KismetTextLibrary) : seul le nœud des dumps est lu (F13).
Repris d'ORG4S § 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`).
## 7. Critères de VAL (commande → attendu), V5 et V6 mis à jour
### 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 (6273 noeuds) ===` (6271 sans garde, 6269 `IsMale` seul, 6270 hommes seuls : variantes écartées) ; et (Grep **en nommant le fichier**, les `.txt` de `etat\` étant ignorés par ripgrep) :
- O4a : critères de ORG4S § 7 V5.1 (première puce) inchangés (`CustomEvent_702.then` → `O4a-B.execute` seul, `O4a-B.else` → `O4a-S.execute`, `Rate` = 0.25, `VariableGet_720.PersonCumming` → 3 cibles, `Condition` reliée) ;
- O4c : `IfThenElse_875.then` → `O4c-L.Exec` **seul** ; `IfThenElse_875.else` → `MacroInstance_18.exec` inchangé ; `CallFunction_11423.execute` ← **3 sources** (`O4c-L.Completed`, `CallFunction_32955.then`, `IfThenElse_189.then`) ; `O4c-L.Array` ← `VariableGet_3498.SexPersons` (qui garde `GetArrayItem_1037.Array`) ; `O4c-L.Array Element` → **5 cibles** (`O4c-V.Object`, `O4c-M.self`, `O4c-N.self`, `O4c-G.self`, `O4c-R.self`) ; `O4c-L.LoopBody` → `O4c-B0.execute` ; `O4c-B0.then` → `O4c-B1.execute` ; **condition du sexe** : `O4c-N.Genital` → `O4c-T.InText` ; `O4c-T.ReturnValue` → `O4c-E.A` ; `O4c-E.B` = `Penis` (à l'octet) ; `O4c-M.IsMale` → `O4c-O.A` ; `O4c-E.ReturnValue` → `O4c-O.B` ; `O4c-O.ReturnValue` → `O4c-B1.Condition` ; `O4c-B1.then` → `O4c-B2.execute`, `O4c-B1.else` → `O4c-B3.execute` ; `O4c-C1.A` et `O4c-C2.A` ← `O4c-G.Sex_Orgasm` ; `O4c-C1.B` = 90, `O4c-C2.B` = 100 ; `O4c-B2.else` → `O4c-Ph.execute`, `O4c-B3.else` → `O4c-Pf.execute` ; `O4c-Ph.then` et `O4c-Pf.then` → `O4c-R.execute` ; `O4c-R.self` ← `O4c-L.Array Element` ; **impasses** `O4c-B0.else`, `O4c-B2.then`, `O4c-B3.then`, `O4c-R.then` : aucun lien ; les 4 Branches ont leur `Condition` reliée ; `InString` des deux marqueurs à l'octet (`ORG4 bonus Endsex homme` / `… femme`), `bPrintToScreen` faux ; `O4c-E` affiché `KismetStringLibrary::EqualEqual_StriStri()`, `O4c-T` `KismetTextLibrary::Conv_TextToString()`, `O4c-O` `KismetMathLibrary::BooleanOR()`.
- Comptes relatifs au dump P1 (mêmes Grep, fichier nommé) : `macro 'ForEachLoop'` **+1** (GI-P2 : 79 lignes, baseline P1 à refaire) ; `GiveOrgasmReward` 0 → **1** ; `PrintString` **+2** ; `variable 'IsMale'` **+1** (GI-P2 : 25) ; `variable 'Genital'` **+1** (baseline P1) ; `Conv_TextToString` **+1** ; `EqualEqual_StriStri` **+1** ; `BooleanOR` **+1** ; `variable 'Sex_Orgasm'` 0 → **1** ; `Sex_OrgasmCounts` **0 → 0** (aucune occurrence dans GI avant, aucune après : règle commune § 2.6 point 2) ; aucun appel `…::Cum()` nouveau.
- Non-régression (un par un) : `-Fn=isSameAs` → 11 ; `-Fn=GetVariable` → 53 ; `-Fn=CallFunctionReturnBool` → 594 ; `-BP=Action -Fn=EventGraph` → 363.
2. **Diff indépendant** : `python -I Tools\DiffRemplacementNoeuds.py <dump P1> <dump après> <profil>` → seuls les nœuds et liens des § 2.2-2.4 ; « pins modifiés sur nœuds communs » = **7** : `CustomEvent_702`, `VariableSet_9760`, `CallFunction_960`, `VariableGet_720` (O4a), `IfThenElse_875`, `CallFunction_11423`, `VariableGet_3498` (O4c) — la chaîne `Genital` ne touche aucun nœud existant (elle part de `O4c-L.Array Element`) ; `GetArrayItem_1037` n'est **plus** touché (il l'était avec O4b : 8 nœuds en ORG4S) — et aucun autre.
3. **Compilation** : `compile_blueprint … warnings_as_errors:true` → `null`, journal de l'éditeur sans Error / Warning pour GI ; `CompileAllBlueprints` éditeur fermé : 0 erreur (critère requalifié le 2026-10-13, ORG4S § 7) ; `LPTestStringCompat` **3120 / 0 / 60** (`lp-validate`).
4. **Empreintes** : `md5sum Content/BPs/GI.uasset` noté ; `Person.uasset` = `8668a47c627f7a5254910cf0ac33b12a` et `SexAction.uasset` = `a8705f7fbe1fde1daba0464bfc9ff9b5` inchangés ; Room et PC : valeur relevée à l'entrée = à la sortie ; `git status --short -- Content` : aucun fichier de plus que ` M` GI, Person, Room, PC.
### V6 — essai en jeu (build Development empaqueté par BUILD, **même ligne de commande que HJ** : `-ScriptStackOnWarnings -LPHitchLog` ; UE-GO / BUILD-GO de l'orchestrateur)
**Ce que le journal montre / ne montre pas** : les marqueurs O4c sont les **seules** lignes de journal du bonus (`ModifyStat` ne laisse aucune ligne, ORG4S § 7 V6) ; l'effet sur les stats se voit à l'écran (texte de `ModifyStat`) et est rapporté par l'utilisateur. Les lignes ORG5 (`Bonus : orgasme de <nom> (compteur <n>)`, ORG5S:134) n'existent que si **ORG5-I1 est dans le build** ; sinon, les contrôles ORG5 sont `sans objet : ORG5-I1 absent du build`.
**Parcours à jouer** (une scène avec le joueur ; noter pour chaque participant son `IsMale` et son `Genital`, et qui est `SexPersons[0]`) :
- **S1 (bonus homme)** : scène MF ; laisser l'homme (`IsMale` vrai) entre 90 et 100 (texte rouge « Close to cumming… » visible), la femme sous 100 ; cliquer « Finish having sex ». Attendu : fin dans la même image ; texte de stat du bonus pour l'homme (`mood` +20 si c'est le joueur, `attractiontoplayer` sinon), rien pour la femme ; **1** marqueur `… homme`, **0** `… femme`.
- **S2 (femme qui vient de jouir)** : scène MF ; laisser la **femme** atteindre 100 (orgasme automatique, jauge remise à 0), l'homme ≥ 90 ; cliquer « Finish having sex » aussitôt. Attendu : **1** marqueur `… homme`, **0** `… femme` ; si ORG5 : **1** ligne `Bonus : orgasme de <femme>` (l'orgasme réel), située **avant** la ligne `Endsex (Animation String)` de S2. *Remplace le parcours « les deux ≥ seuil » de la fiche : une femme à 100 ne peut pas exister au moment du clic (F4).*
- **S3 (témoin sous le seuil)** : démarrer une scène, cliquer « Finish having sex » aussitôt (jauges < seuils). Attendu : fin de scène ; **0** marqueur ; 0 ligne ORG5 ; 0 avertissement.
- **S4 (pas de double bonus avec `Finish`)** : homme ≥ 90 ; choisir une animation « Cum on … » (`Person::Cum` : bonus de base 1×, ORG5 1×), puis « Finish having sex » aussitôt. Attendu : **0** marqueur O4c (jauge remise à 0) ; si ORG5 : exactement **1** ligne `Bonus : orgasme de <homme>` (celle du `Cum`), avant la ligne `Endsex`.
- **S5 (un non-éligible ne bloque pas)** : scène où l'index 0 est sous le seuil et l'index 1 au-dessus (par exemple MM, l'un < 90, l'autre ≥ 90) ; cliquer « Finish having sex ». Attendu : **1** marqueur `… homme` (le second) ; fin de scène normale. Si aucune scène MM n'est disponible : noter « non rejoué » (la preuve statique est V5).
- **S6 (personnage à pénis non `IsMale`, décision Q2)** : scène avec un personnage **`IsMale` faux et `Genital = 'Penis'`** (femme à pénis : scène FF avec l'étiquette `Shemale`, ou MF dont la partenaire a un pénis ; le jeu le prévoit, F16 ; création au chargen non lue, Q-ORG4c-7) ; l'autre participant est une femme sans pénis, sous 100. Laisser le personnage à pénis entre 90 et 100 (texte « Close to cumming… » visible si c'est l'index 0 d'une scène filtrée FF avec `Shemale` ou MF, P-STG:17376-17417), cliquer « Finish having sex ». Attendu : **1** marqueur `… homme` (le personnage à pénis, seuil 90), **0** `… femme` ; texte de stat du bonus pour lui seul. *C'est la seule preuve en jeu que le côté droit du OU (`Genital`) fonctionne seul, `IsMale` étant faux.* Si le personnage ne peut pas être obtenu : noter « non rejoué » (V5 prouve les liens ; le dump montre `Conv_TextToString` et `EqualEqual_StriStri` sur `Penis`).
**Greps sur le journal du jeu** (mode `count`, fichier nommé ; base = HJ de ORG4S) :
| Motif | Attendu |
|---|---|
| `Endsex \(Animation String\)` | **6** (un par scène S1 à S6) — **preuve que le parcours est rejoué** (sans elle, un 0 ne prouve rien) ; 5 si S6 non rejoué |
| `ORG4 bonus Endsex homme` | **4** (S1, S2, S5, S6) ; 3 si S6 non rejoué |
| `ORG4 bonus Endsex femme` | **0** (branche non rejouable, R-ORG4c-2) |
| `ORG4 bonus Endsex` (préfixe) | **4** (= somme) ; 3 si S6 non rejoué |
| `Bonus : orgasme de` (si ORG5-I1) | **2** (S2 femme, S4 homme), et **aucune** ligne de ce motif **après** une ligne `Endsex (Animation String)` avant le début de la scène suivante (Grep `-n` des deux motifs, comparer les numéros de ligne) : un clic `Endsex` ne produit jamais de ligne ORG5 |
| `Accessed None trying to read \(real\) property PersonCumming` | **0** (HJ : 2) |
| `GiveOrgasmReward\|OrgasmIrBoost` (piles d'avertissement) | **0** |
| `Accessed None` avec `Genital` ou `IsMale` (nouvelles lectures de O4c) | **0** |
| `fatal\|Unhandled\|Critical\|Assertion` | **0** |
| `LogScript: Warning: Accessed None` | ≤ 11 (indicatif, HJ : 13) |
Non-régression : `.\Tools\LogStats.ps1 -Compare <journal>,<HJ>` : aucune famille nouvelle ; G13 et G16 intacts.
**Règle commune (ORG4 / ORG5)** : le contrôle est la combinaison de S2, S4 et de la dernière ligne ORG5 du tableau : **un clic `Endsex` = au plus 1 marqueur par personne et 0 ligne ORG5** ; **un orgasme réel = 1 ligne ORG5 par personne et 0 marqueur O4c** ; le bonus de base d'un orgasme réel n'a pas de marqueur (§ 2.6 point 4) : observé à l'écran seulement.
**Limites** : la branche « non homme » (seuil 100) n'est pas rejouée ; l'effet réel des stats n'est vu qu'à l'écran ; le cas « élément invalide dans `SexPersons` » n'est pas rejoué ; l'ordre des index n'est pas lu (S5 l'observe) ; S6 dépend de la disponibilité d'un personnage à pénis non `IsMale`.
Fichiers à commiter (dépôt jeu, branche `ue5.8`, ticket au gardien) :
- A `Docs/Migration/etat/ST/STE/STE-ORG4c-SPEC.md`
Tours : 35 / 47 (35 de la fiche + 12 de prolongation demandés par l'orchestrateur ; compte de l'agent : 30 pour la SPEC initiale, 5 pour le complément Q2, remise du compte rendu comprise ; `python -I Tools/FicheStats.py --lot STE` fait foi)
## Constats
- Lecture seule respectée ; un seul fichier écrit (ce livrable, non suivi). Aucun nom d'utilisateur ni chemin de profil cité. Aucun `>` dans les commandes Bash ; aucun refus du crochet `ecriture-gardien` rencontré.
- **Méthode du complément** : l'orchestrateur demandait un complément « par Edit, sans réécrire le fichier » ; l'agent `lp-cart` n'a pas l'outil Edit (`sk-protocol` § 7 : un seul Write complet, correction = Write complet). Le complément Q2 a donc été fait par un Write complet qui conserve le texte existant (dont la section « Décisions de l'utilisateur » ci-dessous, reprise à l'identique) et ne modifie que : titre, Annonce, F2, F13 à F16, § 1.3, P1, P4, P6, P7, § 2.1, § 2.3 à 2.5, repli § 3 (v, vi), R-ORG4c-2/3/10 à 12, Q#, § 5, § 6, § 7 (V5, V6 : S6 ajouté).
- **Établi** : F1 (variable `IsMale`), F2, F3, F5, F5b, F6 (précédent de corps en impasse), F8, F9 (types créés), **F13** (précédent exact de la chaîne `Genital` dans Person et dans GI), **F14** (`ORBoolean` créé en Room), **F15** (insensible à la casse, lu dans le moteur), la règle commune (ORG4S:265-269) et ses points d'appui dans P-STG. **Estimé** : F4, conclusion « 100 inatteignable à `Endsex` » (écrivains de `Sex_Orgasm` lus dans les graphes dumpés seulement ; fonctions annexes de Person et mods non lus) ; comportement des créatures ; ordre d'index. **Incertain** (essai qui tranche) : création de `Utilities|Array|ForEachLoop` et des six autres type_id jamais créés (`find_node_types` en P5 / P7, avec contexte pour la conversion et l'égalité) ; valeur `ForceEnd` de `SexAction` (P0) ; relecture de la longueur de tableau par la macro (V6-S5) ; existence rejouable d'un personnage à pénis non `IsMale` (V6-S6, Q-ORG4c-7).
- Pièges Grep : les `.txt` de `etat\` sont ignorés par ripgrep même avec le dossier en `path` : nommer le fichier (rappel, ORG4S « Constats »). Les dumps PC et PASA portent le préfixe `LogLPDump: Warning:` sur chaque ligne ; un motif non ancré fonctionne. Un dump `-Pins -Exec` contient deux blocs à en-tête identique : les comptes de lignes d'un Grep portent sur les deux.
- Hors périmètre, noté : `GI::EndSex` donne `mood +50` / `arousal -50` à chaque participant indépendamment de l'orgasme (F-ORG2, ORG4S « Constats »).
## Décisions de l'utilisateur (2026-10-14, session STE)
- Q-ORG4c-1 : seuil femme **100 gardé tel quel** (branche sans effet en pratique, accepté).
- Q-ORG4c-2 : homme = **`IsMale` OU `Genital == 'Penis'`** (même règle que « Close to cumming ») : la SPEC est à compléter (nœuds en plus).
- Q-ORG4c-3 : **`>= 90`** (et `>= 100`).
- Orchestrateur : Q-ORG4c-4 garde `IsValid` par élément **oui** ; Q-ORG4c-5 deux libellés, pas de marqueur à l'orgasme réel ; Q-ORG4c-6 IMPL sous UE-GO avec P0.
- Intégration (agent lp-cart, 2026-10-14) : Q-ORG4c-2 complétée dans les § 1.3, 2.1, 2.3, 2.4, 2.5, 3, 4, 7 ; totaux O4a + O4c = 20 nœuds, 2 coupures, 32 liens, 8 valeurs, `GI:EventGraph` 6 273.
- Q-ORG4c-7 (utilisateur, 2026-10-14) : **oui**, un personnage non `IsMale` avec pénis peut être créé en jeu : le parcours **S6 est rejoué** en V6 (attendus : 6 clics `Endsex`, 4 marqueurs `homme`, 0 `femme`).
## P0 levé (orchestrateur, 2026-10-14)
- Dump `dumps\SexAction__EventGraph_P0.txt` (310 nœuds, SexAction `A8705F7F`, journal `Saved\Logs\portage\STE-ORG4_LPDumpFunction_20261014-015407.log`) : `SwitchString_0.Endsex` → `K2Node_CallFunction_8` = `GI_C::Cum()` avec **`ForceEnd = 'true'`** (l. 73, 232-236). Hypothèse établie : O4a + O4c exécutables.