LifePlay-Revival/Docs/Migration/etat/ST/STE/STE-ORG4c-SPEC.md

332 lines
60 KiB
Markdown
Raw Normal View History

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.