Fiche STE-ORG5 — Niveau N3 — Modèle prévu (modèle de l'agent lp-cart) | utilisé claude-sonnet-5-5 — Agent lp-cart — Skills lp-mcp (lecture), sk-protocol (préchargés avec l'agent : ue-cpp-build, lp-commandlets, lp-paths)
STE-ORG5-SPEC : reconstruction du bonus d'orgasme de l'auteur (grille de récompenses), découpage en fiches et version minimale pour l'alpha (2026-10-14)
Hors gabarit : les sections suivent l'ordre du gabarit SPEC (1 objectif, 2 fichiers touchés et ordre, 3 repli, 4 risques et questions, 5 interdits, 6 valeurs moteur, 7 critères de VAL) ; les rubriques demandées par la fiche (rubrique 7) sont des sous-sections : comportement cible = 1.1, table des 20 entrées = 1.2, formule = 1.3, conception 5.8 = 2.1 à 2.3, widgets et fonctions = 2.4, option DisableBonus = 2.5, découpage en fiches = 2.6, version minimale pour l'alpha = 3.1, estimation = 4.1, risques = 4.2, lectures MCP manquantes = 4.3, Q# = 4.4. Annexes A (commandes et lectures, comptes bruts) et B (établi / estimé / incertain) après la section 7. Lecture seule : ni éditeur, ni MCP, ni commandlet, ni build, ni jeu ; l'exécutable de l'auteur n'a pas été lancé ; aucun fichier du projet modifié hormis ce livrable. Aucun refus du crochet (outil de lecture : cinq scripts Python en fichier dans le scratchpad de session, le désassembleur kdis.py / kdbg.py / kall.py, calc.py et strs.py, lancés par python -I <fichier> en 20 exécutions, aucune écriture hors scratchpad). Changement par rapport à l'audit : le désassemblage du bytecode de PopulateBonusRewards (L14) et de GiveOrgasmReward (L15) est fait ; il corrige trois points de STE-ORG-AUDIT.md § 9 (voir 1.1, 1.3 et 2.5 : trois récompenses au plus et non cinq ; valeur à 100 = 0,2 ; branche DisableBonus résolue).
Sigles
| Sigle |
Chemin |
Contenu |
| B |
D:\XxX\LifePlay_2023_04_Stable_64bit\LifePlay\Content |
build cuit de l'auteur, version 2023.04 Stable, UE 4.20, sans .pak ; les nombres après B\…\X.uexp sont des offsets d'octets absolus du .uexp |
| O |
D:\Game\LifePlay-master 5.8\Content |
nos assets (copie 5.8) |
| P-STG |
D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STG\dumps\Person__EventGraph.txt |
dump de l'EventGraph de Person (copie de travail) |
| L6f-G / L6f-P |
…\etat\portage55\L6f\L6f_dump_GI.txt / L6f_dump_Person.txt |
dumps 5.5 de tous les graphes |
| AUD |
…\etat\ST\STE\STE-ORG-AUDIT.md |
audit amont |
| DIS |
scratchpad de session : kdis.py, kdbg.py, kall.py |
désassembleur Kismet (Python, lecture seule), voir annexe A |
1. Objectif mesurable
Reproduire dans les sources 5.8 le bonus d'orgasme de l'auteur (build 2023.04 Stable) : à chaque orgasme, jusqu'à 3 récompenses « stat ±valeur » tirées parmi 20 clés filtrées par les tags de la position, valeur décroissante avec la stat, application de la récompense choisie par ModifyStat, option de désactivation. Critères mesurables (reprennent la section 7) : (i) table de 1.2 identique (20 clés, mêmes tags) ; (ii) les 21 valeurs de 1.3 reproduites ; (iii) jamais plus de 3 récompenses ; (iv) application = un seul ModifyStat(Stat, Change, DifficultyAdjusted = false, NoDisplay = false) sur la personne qui vient de jouir ; (v) option désactivée : aucune récompense, bonus ancien intact ; (vi) version minimale : 0 asset modifié.
1.1 Comportement cible (établi par désassemblage du bytecode de B, sauf mention)
| # |
Comportement |
Source |
Niveau |
| E1 |
Déclencheur : chaque exécution de l'événement GiveOrgasmReward de Person, donc chaque orgasme de toute personne (joueur ou PNJ). JUMPIFNOT sur GI.DisableBonus : faux → copie de GI.CurrentTags dans une structure StringArray, puis GI.Cursor.PopulateBonusRewards(self, tags), puis JUMP vers le bonus ancien ; vrai → saute directement au bonus ancien. Le bonus ancien est exécuté dans les deux cas (OrgasmIrBoost, mood +20 du joueur, attractiontoplayer ×3 ou ×6) : la grille s'y ajoute |
B\BPs\Person.uexp:21111 (JUMPIFNOT m413 (GI.DisableBonus)), :21184 (StringArray), :21218 (appel), :21262 (JUMP vers :21135), :21135-21652 (bonus ancien, identique à P-STG:16059-16110 et 17453-17496) |
établi |
| E2 |
Appel : PopulateBonusRewards(Person, Tags) est un talon qui copie ses deux paramètres et appelle ExecuteUbergraph_Cursor(10856) ; l'entrée 10856 saute à l'instruction m15 |
B\UI\Cursor.uexp:14450-14487 (talon), :14006 (JUMP m15) |
établi |
| E3 |
Temporisation : RetriggerableDelay(0,2 s) avant tout : un second appel dans les 0,2 s remplace le premier (comportement documenté du nœud, non relu dans le .cpp) ; seul le dernier orgasme produit des récompenses (« last person who came ») |
Cursor.uexp:7141 ; signature moteur KismetSystemLibrary.h:700-701 |
établi pour le nœud, estimé pour le remplacement |
| E4 |
Remise à zéro : ScrollBonuses.ClearChildren(), lastCum := Person |
Cursor.uexp:7198, :7218 |
établi |
| E5 |
Candidats : Map_Keys(statTags) (20 clés), Array_Shuffle, Array_Resize(·, 10) : 10 clés au hasard ; countBR := 0 |
Cursor.uexp:7236, :7281, :7306, :7336 |
établi |
| E6 |
Boucle sur les 10 clés (tant que la sortie anticipée n'est pas levée), pour chaque clé : (a) tags := statTags[clé].Strings ; (b) GI.Overlaps(Tags.Strings, tags, IfEmptyThenTrue = true) : faux → clé ignorée ; (c) si clé = attractiontoplayer : exige NON Person.isPlayer ET GI.IsInterestedIn(Person, GI.PlayerCharacter) ET GI.SexPersons contient GI.PlayerCharacter, sinon ignorée ; (d) acceptation : countBR++, création d'un widget BonusReward, Person, Stat = clé sans le - final, x := Person.QueryStat(Stat, false, false).Value, Change := signe × valeur(x) (1.3), ScrollBonuses.AddChild ; (e) NotEqual_IntInt(countBR, 3) : à 3 acceptées, sortie de boucle. Au plus 3 récompenses |
(a) Cursor.uexp:7545-7586 ; (b) :7606-7651 ; (c) :7692-7743 et :8686-8884 ; (d) :7753-8576 ; (e) :8607-8629, :8889 |
établi (la constante 3 est dans le code ; le journal 5.26 disait 5, Change_Logs.txt:39, le code du build 2023.04 fait foi) |
| E7 |
Widget BonusReward : bouton RewardButton + texte RewardText lié à Format("{stat} {sign}{change}"), signe vide si Change < 0 sinon +, change argument flottant. Clic : Person.ModifyStat(Stat, Change, false, false) puis GetParent().ClearChildren() (retire les 3 boutons). Aucune pause du jeu, aucun appel de son dans le bytecode |
B\UI\BonusReward.uexp:1371-1973 (texte), :1115-1201 (clic) |
établi |
| E8 |
Texte d'en-tête (Cursor.Get_TextBlock_0_Text_0) : DisableBonus → « Bonus rewards disabled » ; sinon si ScrollBonuses a des enfants → « Pick a bonus reward for {Name_First}'s last orgasm » ; sinon « Bonus rewards can be chosen here after each orgasm » |
Cursor.uexp:22465-23015 |
établi |
| E9 |
Visibilité du panneau SexExclusives : visible si GI.SexOn, sinon replié ; l'appartenance de TextBlock_0 et de ScrollBonuses à ce panneau n'est pas lue (arbre de widgets non lu) |
Cursor.uexp:19759-19818 |
établi pour la fonction, non établi pour l'arbre |
| E10 |
Aucun nettoyage des récompenses en fin de scène : les 45 fonctions décodées de Cursor ne touchent ScrollBonuses, lastCum, countBR, statTags que dans PopulateBonusRewards et Get_TextBlock_0_Text_0 ; seuls Person, BonusReward et Cursor citent ces noms (annexe A, point 8). Les boutons restent jusqu'au clic ou au prochain orgasme |
annexe A points 8 et 9 |
établi |
1.2 Table des 20 entrées (statTags, valeur par défaut de la variable, relue à la source)
Clé finissant par - : la récompense baisse la stat (signe −1, nom de stat sans le -). « vide » : Overlaps renvoie vrai quelles que soient les tags de la position (drapeau IfEmptyThenTrue à vrai). Offset = chaîne dans B\UI\Cursor.uexp (annexe A point 6).
| # |
Clé |
Tags de position |
Offset |
# |
Clé |
Tags de position |
Offset |
| 1 |
perversion |
vide |
4643 |
11 |
likes_missionary |
Missionary |
5450 |
| 2 |
masochist |
Aggressive, AggressiveFM |
4703 |
12 |
likes_oral |
Oral, Blowjob, Cunnilingus, LickPussy, LickAss, Rimjob |
5531 |
| 3 |
prone_to_orgasm |
vide |
4794 |
13 |
likes_rcowgirl |
ReverseCow, ReverseCowgirl |
5665 |
| 4 |
attractiontoplayer |
vide (+ condition E6c) |
4859 |
14 |
likes_rough |
Aggressive, AggressiveFM |
5763 |
| 5 |
fitness |
Penetration, Foreplay, Cum |
4927 |
15 |
likes_sidefuck |
Spooning, Sidefuck, Spoon |
5856 |
| 6 |
likes_anal |
Anal |
5021 |
16 |
likes_toys |
Toys, Dildo, Vibrator |
5956 |
| 7 |
likes_boobjob |
Titfuck, Boobjob |
5090 |
17 |
likes_tribadism |
Tribadism, Scissor, Scissoring |
6048 |
| 8 |
likes_cowgirl |
Cow, Cowgirl |
5177 |
18 |
likes_vaginal |
Vaginal |
6154 |
| 9 |
likes_doggy |
Doggy, Doggystyle |
5260 |
19 |
masochist- |
Aggressive, AggressiveFM |
6229 |
| 10 |
likes_handjob |
Handjob, RubPussy, FingerPussy |
5346 |
20 |
prone_to_orgasm- |
Penetration, Foreplay, Cum |
6321 |
- Identique à
AUD § 9.4 (relue indépendamment, mêmes 20 clés, mêmes tags). Deux groupes partagent les mêmes tags : {1 masochist, 14 likes_rough, 19 masochist-} et {5 fitness, 20 prone_to_orgasm-}.
- Les 18 stats (hors les deux clés en
-) existent comme .lpstat chez l'auteur et chez nous (AUD § 9.4, 9.9 point 7 ; non rejoué).
- Les 34 mots de tags figurent tous dans
O\BPs\GI.uasset (grep -a -o -w -F, annexe A point 10 : Penetration 396, Foreplay 158, Cum 33, Anal 215, Vaginal 327, Missionary 148, Titfuck 3, Tribadism 2…), ce qui rend les tags atteignables en principe (estimé : le vocabulaire d'animations de GI ; la valeur réelle de Anim.Tags n'est pas lue).
- Exemple (calculé sur la table) : position
{Missionary, Vaginal, Penetration} → éligibles perversion, prone_to_orgasm, attractiontoplayer (si condition), fitness, likes_missionary, likes_vaginal, prone_to_orgasm- = 7 clés sur 20 ; CurrentTags vide → les 20 passent.
1.3 Formule de la valeur (établi pour les constantes et l'ordre, mesuré pour la table)
Change = signe × ceil((2,0 − MapRangeClamped(|x|, 0, 100, 0, 1,9)) × 10) / 10, x = valeur courante de la stat (QueryStat), signe = −1 si la clé finit par -, sinon +1. Instructions : Abs Cursor.uexp:8339, MapRangeClamped(·, 0, 100, 0, 1.9) :8360, Subtract(2, ·) :8401, Multiply(·, 10) :8427, FCeil :8453, Conv_IntToFloat :8474, Divide(·, 10) :8495, Multiply(·, signe) :8521, SelectFloat(−1, 1, EndsWith) :8308.
Table calculée (script calc.py, double = arithmétique des Blueprints UE 5.x, float32 = UE 4.20 de l'auteur ; identiques sur les 21 points) :
| x |
0 |
1 |
5 |
10 |
20 |
25 |
30 |
40 |
45 |
50 |
55 |
60 |
70 |
75 |
80 |
90 |
95 |
99 |
100 |
120 |
−30 |
| valeur |
2,0 |
2,0 |
2,0 |
1,9 |
1,7 |
1,6 |
1,5 |
1,3 |
1,2 |
1,1 |
1,0 |
0,9 |
0,7 |
0,6 |
0,5 |
0,3 |
0,2 |
0,2 |
0,2 |
0,2 |
1,5 |
Lecture : 1,1 vers x = 50 (accord avec « fitness +1.1 » et « prone_to_orgasm -1.1 » des captures) ; 100 donne 0,2 et non 0,1 (arrondi flottant de 2,0 − 1,9 ; corrige l'hésitation de AUD § 9.5). Le rendement dépend de la valeur de la stat, pas du nombre d'orgasmes. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2. Fichiers touchés, ordre
2.1 Conception 5.8 : trois options
| Critère |
A. Blueprint fidèle (comme l'auteur) |
B. C++ autonome (recommandée) |
C. Hybride (C++ pour table / tirage / formule, BP pour les widgets) |
| Assets créés / modifiés |
Cursor (variables statTags, Stats, countBR, lastCum, widgets ScrollBonuses et TextBlock_0, fonction, liaison de texte), BonusReward (nouveau), Person (+ ~6 nœuds), GI (DisableBonus + 2 nœuds Save / Load, GI.uexp:866870 et :869178 chez l'auteur), GameSettings (champ), SettingCheckbox / MainMenu (case) |
aucun (version minimale) ; 2 fichiers C++ neufs |
Cursor (widgets + appel), BonusReward (nouveau), Person (1 nœud), + 2 fichiers C++ |
| Dont modifiés par d'autres lots |
Person (STG), GI (STG B7-a) : oui, git status du 2026-10-14 : M sur GI, Person, Room |
aucun (Room non touché) |
Person : oui |
| Faisable par MCP |
nœuds : oui en principe (BlueprintTools, ~70 instructions décodées de 7141 à 8896 ≈ 60 à 80 nœuds, estimé) ; arbre de widgets : non démontré (seuls scene.SceneTools, blueprint.BlueprintTools, asset.AssetTools, object.ObjectTools apparaissent dans les 40 premières occurrences de editor_toolset.toolsets.* des Docs ; aucun toolset de widget vu, recherche tronquée) ; valeur par défaut d'une Map<String, StringArray> : non démontrée |
sans objet (pas de MCP) |
nœuds oui ; widgets : mêmes réserves que A |
| Précédent dans le dépôt |
aucun pour de l'UMG créé par MCP |
UI construite en C++ sans toucher de Blueprint : LPSettingsSubsystem.h:6 (« Aucun Blueprint n'est modifié »), LPColorGradeSubsystem.cpp:188-302 (lignes injectées dans SettingsScrollBox), LPModInfoSubsystem.cpp:288-307 (cases), LPKeyboardSubsystem.cpp:636, LPDirectControlSubsystem.cpp:1259, LPCameraModeSubsystem.cpp:469 (panneaux Slate par AddViewportWidgetContent) ; appels de fonctions Blueprint par FindFunction + ProcessEvent : LPDirectControlSubsystem.cpp:411-455, LPDataCompat.cpp:149-164, LPPersonPropGuardSubsystem.cpp:129-131 ; réglages joueur hors GameSettings.sav : LPUserSettings.h:3-9 |
mixte |
| Build C++ |
aucun |
oui (module LifePlay, dépendances Slate, SlateCore, UMG déjà présentes LifePlay.Build.cs:38) |
oui |
| Apparence |
identique à l'auteur (police et styles du jeu) |
panneau Slate au style à régler (police et couleur à copier d'un widget existant, comme LPColorGradeSubsystem.cpp:289-297) |
identique à l'auteur |
| Testabilité hors jeu |
faible |
table, tirage et formule en fonctions statiques pures, contrôle de formule au démarrage |
moyenne |
| Effort estimé |
5 à 8 sessions MCP (estimé, 4.1) |
3 fiches pour la version minimale, 3 de plus pour la grille |
4 à 5 sessions MCP + C++ |
Recommandation : B. Raisons : (1) aucun asset partagé touché (Person, GI sont en cours de modification par STG, Room par CAM) ; (2) aucune dépendance à des capacités MCP non démontrées (widgets, valeur par défaut de map) ; (3) tout le dépôt a déjà ce mode de construction ; (4) la version minimale n'a aucune interface, ce qui évite le point que l'auteur désigne comme suspect (Change_Logs.txt:34, plantages autour des orgasmes). Réserve : l'apparence du panneau (version 1) ne sera pas pixel-identique à celle de l'auteur. A et C restent possibles si l'utilisateur veut l'identique : elles exigent d'abord la lecture L-M1 (4.3). |
|
|
|
2.2 Accroche à l'orgasme : deux manières, une seule active
|
H1. Sondage en C++ (recommandée pour l'alpha) |
H2. Un nœud dans GiveOrgasmReward |
| Principe |
le sous-système lit à 0,1 s GI.SexOn et, pour chaque GI.SexPersons[i], Person.Sex_OrgasmCounts : une hausse = un orgasme (la macro IncrementInt est dans l'événement Cum, P-STG:16118-16125 ; remise à 0 avec Sex_Energy et Sex_BoredCountdown, P-STG:15908-15911 et 16175-16178 : une baisse = remise à zéro, on resynchronise sans récompense) |
un nœud CallFunction (fonction statique C++ NotifyOrgasm(Person)) inséré entre K2Node_CustomEvent_87.then et K2Node_CallFunction_1005.execute (P-STG:16059-16061) : 1 nœud, 3 liens |
| Assets touchés |
aucun |
Person.uasset (STG + CAM non commités : annonce à Big Boss, instantané, session MCP, compilation, CompileAllBlueprints) |
Couvre Endsex (STE-ORG4) |
oui si ORG4 passe par Person::Cum (le compteur monte) ; non si ORG4 appelle seulement GiveOrgasmReward |
oui dans les deux cas |
| Double déclenchement |
impossible : un incrément par Cum ; deux orgasmes en moins de 0,2 s : seul le dernier compte (comme l'auteur, E3) |
idem ; si H2 est ajouté plus tard, il écrit le compteur observé pour que H1 ne redéclenche pas |
STE-ORG4-SPEC.md n'existe pas encore (Glob STE-ORG4* dans le dossier du lot : seule la fiche fiches\STE-ORG4.md) : la compatibilité avec ORG4 est donc non vérifiée (Q-ORG5-6). |
|
|
2.3 Fichiers touchés (option B)
| Fichier |
Action |
Version |
Autre lot concerné |
Source/LifePlay/LPBonusRewardSubsystem.h et .cpp |
créer |
V-min, V-1 |
aucun (fichiers neufs ; git status actuel : LPCameraModeSubsystem.*, LPSaveRelaunch.* non suivis, LPDebugSubsystem.*, LPDirectControlSubsystem.*, LPOutdoorRoomSubsystem.*, LifePlay.cpp modifiés par d'autres lots : non touchés) |
Source/LifePlay/LPSettingsSubsystem.cpp |
1 règle d'onglet (GetName().StartsWith("LPBonus") → onglet Lewd), près de :173-181 |
V-2 |
aucun (fichier non modifié aujourd'hui) |
Content/BPs/Person.uasset |
1 nœud (H2) |
V-3, facultative |
STG, CAM |
Saved/Config/Windows/GameUserSettings.ini (utilisateur, pas le dépôt) |
section [/Script/LifePlay.LPBonusRewardSettings], clé bDisabled |
V-min |
aucun |
Aucun fichier de GI, Cursor, GameSettings, MainMenu, SettingCheckbox, Room n'est modifié par l'option B. Ordre : C++ (V-min) → build → VAL → essai en jeu → panneau (V-1) → réglage (V-2) → H2 (V-3). |
|
|
|
2.4 Widgets et fonctions
(a) Éléments de l'auteur à reproduire (référence, option A / C) :
| Élément |
Contenu |
Source |
Cursor.PopulateBonusRewards(Person : Person, Tags : StringArray) |
E2 à E6 |
Cursor.uexp:14450-14487, :7141-8896 |
Cursor variables |
statTags (Map<String, StringArray>, 20 entrées par défaut), Stats (String[]), countBR (int), lastCum (Person) |
Cursor.uexp:7218-7336 |
Cursor widgets |
ScrollBonuses (ScrollBox ou panneau avec ClearChildren / AddChild / GetChildrenCount), TextBlock_0 + liaison Get_TextBlock_0_Text_0 |
Cursor.uexp:7198, :22465-23015 |
BonusReward (UserWidget) |
variables Person (Person), Stat (String), Change (réel) ; RewardButton (OnClicked) contenant RewardText lié à Get_RewardText_Text_0 |
BonusReward.uexp:1069-1985 |
Person.GiveOrgasmReward |
Branch(GI.DisableBonus) ; faux → MakeStruct StringArray(Strings = GI.CurrentTags) → GI.Cursor.PopulateBonusRewards(self, struct) → rejoint OrgasmIrBoost |
Person.uexp:21111-21262 |
(b) Conception C++ (option B), signatures à respecter :
UCLASS(config = GameUserSettings) class ULPBonusRewardSettings : public UObject // dans LPBonusRewardSubsystem.h
UPROPERTY(config) bool bDisabled = false; // équivalent de DisableBonus
struct FLPBonusStat { FString Key; TArray<FString> Tags; }; // 20 entrées, section 1.2
UCLASS() class ULPBonusRewardSubsystem : public UGameInstanceSubsystem
Initialize / Deinitialize // FTSTicker 0,1 s, comme LPColorGradeSubsystem.h:51
bool Tick(float); // sondage 2.2 H1 ; débounce 0,2 s ; (V-1) retrait différé du panneau
static const TArray<FLPBonusStat>& Table();
static double RewardChange(double X, bool bNegative); // formule 1.3, ordre des opérations conservé, en double
static bool Overlaps(const TArray<FString>& A, const TArray<FString>& B, bool bIfEmptyThenTrue); // GI.Overlaps, B:1073624-1074121
static void Pick(const TArray<FString>& PositionTags, FRandomStream& Rng, bool bAttractionAllowed,
TArray<FString>& OutStats /*sans le '-'*/, TArray<bool>& OutNegative); // E5-E6, max 3, graine injectable
bool QueryStat(UObject* Person, const FString& Stat, double& OutValue); // FindFunction("QueryStat") + ProcessEvent, sortie Value
bool ModifyStat(UObject* Person, const FString& Stat, double Change); // FindFunction("ModifyStat"), DifficultyAdjusted = false, NoDisplay = false
void OnOrgasm(UObject* Person, const TArray<FString>& TagsCapturedAtDetection);
Algorithme de Pick (équivalent exact de E5-E6) :
Keys = les 20 clés ; Shuffle(Keys, Rng) ; garder 10
Out = []
pour Key dans Keys :
si NON Overlaps(PositionTags, Table[Key].Tags, true) : continuer
si Key == "attractiontoplayer" et NON bAttractionAllowed : continuer
// bAttractionAllowed = NON Person.isPlayer ET GI.IsInterestedIn(WhoIsInterested = Person, WhoInterests = GI.PlayerCharacter) ET SexPersons contient PlayerCharacter
Out.Add(Key sans '-' final, Key finit par '-')
si Out.Num() == 3 : arrêter
Sondage (V-min) : à 0,1 s, si GI.SexOn faux → vider le suivi ; sinon pour chaque personne de GI.SexPersons : premier passage → mémoriser le compteur sans récompense ; hausse → copier GI.CurrentTags, armer Pending = {personne, tags, t + 0,2 s} (remplace un Pending existant) ; baisse → resynchroniser. Quand t est atteint et la personne valide : OnOrgasm. Lecture des propriétés par réflexion, types contrôlés par CastField (précédents : LPCameraModeSubsystem.cpp:40,407, LPShowCoupleSubsystem.cpp:303, LPUserSettings.cpp:14-55 pour réel float ou double) ; type absent ou inattendu : un avertissement journalisé une fois (précédent LogParmsOnce, LPDirectControlSubsystem.cpp:425), jamais de plantage.
Appels Blueprint (réflexion, paramètres par nom, valeurs initialisées puis détruites comme LPDirectControlSubsystem.cpp:426-455) : Person.QueryStat(Stat, WithoutBuff, RNG) sorties Value, Bonus (L6f-P:20-29) ; Person.ModifyStat(Stat, Change, DifficultyAdjusted, NoDisplay) sortie Value (L6f-P:561-567) ; GI.IsInterestedIn(WhoIsInterested, WhoInterests) sortie Interested (L6f-G:23421-23424). Ordre des paramètres de IsInterestedIn dans l'appel de l'auteur non relu : l'IMPL fixe WhoIsInterested = Person (estimé : l'auteur teste « le PNJ s'intéresse au joueur ») et le contrôle en VAL par le journal.
Journal (LogLifePlay, niveau Display), formats imposés pour la VAL : Bonus : orgasme de <nom> (compteur <n>) ; Bonus : <nom> <stat> <±valeur> (x=<valeur>, tags=<n>) ; Bonus : aucune récompense éligible pour <nom> ; Bonus : désactivé (bDisabled) ; au démarrage Bonus : contrôle formule OK (ou Error avec la valeur fautive) sur 0, 10, 25, 50, 75, 90, 100 → 2,0 ; 1,9 ; 1,6 ; 1,1 ; 0,6 ; 0,3 ; 0,2.
V-1 (panneau) : widget Slate SLPBonusPanel (titre vert « Pick a bonus reward for <Name_First>'s last orgasm », au plus 3 boutons « stat ±valeur ») ajouté par GEngine->GameViewport->AddViewportWidgetContent(Panel, ZOrder) (z entre 50 et 200 comme les précédents), SelfHitTestInvisible pour le conteneur et boutons Visible (le reste du jeu garde la souris). Clic : ModifyStat, puis retrait différé au tick suivant (jamais détruire le panneau dans le gestionnaire du bouton cliqué ; estimé : c'est la pratique à éviter, l'auteur le fait avec ClearChildren() dans le gestionnaire). Panneau retiré aussi si GI.SexOn devient faux (écart voulu : l'auteur laisse les boutons, E10). Texte du nombre : formatage par défaut de FText::Format avec un argument flottant ; attendu « 1.1 », « 2 » (non vérifié).
Nom de la personne : Person.Name_First est du texte chez l'auteur (Cursor.uexp:22666, argument de type texte) ; chez nous le type n'est pas lu : accepter FTextProperty et FStrProperty.
2.5 Option DisableBonus (L15 résolu)
| Point |
Constat |
Source |
| Sémantique |
DisableBonus vrai : pas de grille, bonus ancien conservé ; faux : grille + bonus ancien |
Person.uexp:21111 → :21135 (E1) |
| Stockage chez l'auteur |
variable GI.DisableBonus ; copiée dans GameSettings.DisableBonus à l'enregistrement et relue au chargement |
B\BPs\GI.uexp:866870 (GameSettingsInstance.DisableBonus = DisableBonus), :869178 (DisableBonus = GameSettings.DisableBonus) |
| Interface chez l'auteur |
SettingCheckbox : clic → GI.DisableBonus = bIsChecked ; état → BoolToCheckBoxState(GI.DisableBonus) ; libellé « Disable Bonus Orgasm Rewards » dans MainMenu (aucune des 62 fonctions de MainMenu ne cite DisableBonus) |
B\UI\SettingCheckbox.uexp:1921, :13472 ; AUD § 9.7 |
| Message d'aide |
« If you get crashes during sex scenes, Esc > Settings > tick Disable Bonus Orgasm Rewards … » |
B\UI\SexInterface.uexp:42851 (AUD § 9.7) |
| Chez nous |
absent : GameSettings, GI, MainMenu, SettingCheckbox, Cursor, Person ne contiennent pas DisableBonus (AUD § 9.7, non rejoué) ; SettingCheckbox et MainMenu existent (ls O\UI) ; les réglages sont rangés en onglets par ULPSettingsSubsystem, dont Lewd (LPSettingsSubsystem.cpp:35-43, règle de mots :198-203, règle de préfixe de nom :173-181) |
|
| Conception retenue |
réglage C++ hors GameSettings.sav (comme LPUserSettings.h:3-9, LPColorGradeSubsystem.h:7) : ULPBonusRewardSettings::bDisabled dans GameUserSettings.ini ; version minimale : ini seulement ; V-2 : case injectée dans MainMenu.SettingsScrollBox (modèle LPModInfoSubsystem.cpp:288-307) nommée LPBonusCheck… + règle d'onglet Lewd ; aucune sauvegarde de partie touchée (A ajouterait un champ à GameSettings : valeur par défaut faux pour les anciennes sauvegardes, non testé) |
|
2.6 Découpage en fiches (ordre et dépendances)
Les tours sont des estimations (comparées aux budgets des fiches du lot : 45 à 55 tours pour une SPEC N3) ; l'agent exact est à fixer par l'orchestrateur.
| Fiche |
Rôle (agent) |
Niv. |
Contenu |
Dépend de |
Tours |
Jeton UE |
| ORG5-I1 |
IMPL (lp-impl) |
N3 |
LPBonusRewardSubsystem.h/.cpp V-min : table, Pick, RewardChange, sondage H1, QueryStat / ModifyStat par réflexion, application automatique, ini bDisabled, journal, contrôle de formule |
Q-ORG5-1, 2, 3, 4, 5 |
40 |
non (écriture de 2 fichiers) |
| ORG5-B1 |
BUILD (lp-builder) |
N1 |
build du module LifePlay, comptes par Build.ps1 -FromLog |
I1 |
12 |
éditeur fermé (UeState = 0), build partagé avec CAM |
| ORG5-V1 |
VAL (lp-validator) |
N2 |
critères 7.1 à 7.6 (PASS-STATIC) |
B1 |
25 |
CompileAllBlueprints et LPTestStringCompat : sous UE-GO |
| ORG5-J1 |
essai en jeu (utilisateur) |
– |
critères 7.7 à 7.9 |
V1 |
– |
une session de jeu (build empaqueté ; la PIE ne déroule pas ce parcours, lp-mcp § 1 règle 5) |
| ORG5-I2 |
IMPL |
N3 |
V-1 : panneau Slate, 3 boutons, clic, retrait différé |
J1 PASS, Q-ORG5-7, 8 |
55 |
non |
| ORG5-B2 / V2 / J2 |
BUILD / VAL / jeu |
N1 / N2 / – |
idem |
I2 |
12 / 25 / session |
idem |
| ORG5-I3 |
IMPL |
N2 |
V-2 : case dans les réglages + règle d'onglet Lewd |
I2 |
30 |
non |
| ORG5-B3 / V3 |
BUILD / VAL |
N1 / N2 |
idem |
I3 |
12 / 20 |
idem |
| ORG5-I4 |
IMPL par MCP (lp-impl, lp-mcp § 3-4) |
N3 |
H2 : 1 nœud dans GiveOrgasmReward, P1/P2 (MD5 de Person, dumps avant), instantané, compilation, save_assets, dumps après |
libération de Person (STG commité), Q-ORG5-6 |
25 |
oui (MCP, copie partagée ; gel annoncé à toutes les sessions) |
| Option A (non recommandée) : ~8 sessions MCP, ~200 tours, plus la lecture L-M1. |
|
|
|
|
|
|
3. Repli
- Repli de la version minimale : supprimer les deux fichiers neufs (ou
git restore par le gardien) ; aucun asset, aucune sauvegarde à restaurer. Désactivation sans reconstruire : bDisabled=True dans l'ini utilisateur.
- Repli du panneau : revenir à la version minimale (l'application automatique reste).
- Si le build est bloqué ou le jeton UE indisponible avant le 2026-10-16 : rien dans l'alpha, la fonction reste dans le lot STE pour la suite.
3.1 Version minimale pour l'alpha (2026-10-18)
V-min = I1 + B1 + V1 + J1, option B, accroche H1 : à chaque orgasme (toute personne de la scène), tirage exact de E5-E6, application automatique de la première récompense retenue par ModifyStat(Stat, Change, false, false) (la ligne « stat ±n » s'affiche comme celle du mood), journal, ini bDisabled. Ce que V-min laisse de côté : la grille et le choix (E7), le texte d'en-tête (E8), la case de réglage (2.5), l'accroche exacte par GiveOrgasmReward (H2), le nettoyage en fin de scène (sans objet : pas de panneau), la couverture de Endsex si ORG4 n'appelle pas Cum. Ce qu'elle garde : table, filtre par tags, règle de attractiontoplayer, formule, débounce 0,2 s, bonus ancien intact, kill-switch.
Faisabilité (estimée) : ≈ 80 tours d'agents (≈ 2 h) + 1 session de jeu ; build incrémental de référence 18,56 s (STE-H3d_Build_20261013-124425.txt:10, ajout de fichiers non mesuré). Entre dans l'alpha si : Q-ORG5-1 à 5 tranchées le 2026-10-14 ou 15, jeton UE de build libre le 15, V1 PASS-STATIC le 16, J1 le 16 ou 17. V-1 (panneau) : seulement si J1 est PASS le 16 et si Big Boss accepte le risque d'interface (R2) ; sinon après l'alpha. V-2 et H2 : après l'alpha.
4. Risques R#, questions Q#
4.1 Estimation (récapitulatif)
| Périmètre |
Fiches |
Tours |
Sessions MCP |
Sessions de jeu |
Durée d'agent |
| V-min |
I1, B1, V1 |
≈ 77 |
0 |
1 |
≈ 2 h |
| + V-1 (panneau) |
I2, B2, V2 |
≈ 92 |
0 |
1 à 2 |
≈ 2 h 30 |
| + V-2 (case de réglage) |
I3, B3, V3 |
≈ 62 |
0 |
0 à 1 |
≈ 1 h 30 |
| + H2 |
I4 (+ VAL) |
≈ 45 |
1 |
0 |
≈ 1 h |
| Option A complète (comparaison) |
~10 fiches |
≈ 200 |
≈ 8 (estimé : 70 instructions ≈ 70 nœuds ≈ 300 appels MCP, plus widgets et DisableBonus) |
2 |
≈ 8 h |
4.2 Risques
| # |
Risque |
Parade |
| R1 |
Plantages autour des orgasmes : l'auteur a dû ajouter l'option 5.27 faute de reproduire des plantages (Change_Logs.txt:34) ; cause inconnue |
V-min sans widget ni création d'objet UMG dans la pile de l'orgasme ; sondage hors de la pile de Cum ; aucune destruction dans un gestionnaire de clic (V-1) ; ini bDisabled ; journal de chaque étape |
| R2 |
Interface (V-1) : panneau qui capte la souris, mauvais z-order avec le menu d'actions, apparence |
conteneur non cliquable, boutons seuls cliquables ; z-order entre les précédents 50 et 200 ; essai J2 |
| R3 |
Appels par réflexion : nom ou paramètre renommé, type inattendu (réel float ou double) |
recherche par nom, CastField des deux types, avertissement unique, abandon sans effet |
| R4 |
Sondage : faux positif (remise à zéro du compteur, personne qui entre dans la scène), orgasme manqué (scène qui finit avant le tick) |
premier passage = mémorisation sans récompense ; baisse = resynchronisation ; tick 0,1 s ; l'orgasme manqué n'a pas d'autre effet que l'absence de récompense |
| R5 |
Équilibrage : modifier les stats des PNJ (l'auteur le fait) |
identique à l'auteur ; Q-ORG5-4 |
| R6 |
Build partagé avec CAM (Room B2 non commité) et d'autres fichiers C++ modifiés |
fichiers neufs seulement ; un seul build à la fois ; annonce de gel |
| R7 |
ORG4 (fin par Endsex) : un appel direct de GiveOrgasmReward sans Cum n'incrémente pas le compteur |
Q-ORG5-6 ; H2 si nécessaire |
| R8 |
Licence : code de l'auteur sous MIT (Licenses\Vinfamy_License.txt:1, notre copie) ; la reconstruction reprend le comportement lu, pas le code |
commentaire d'origine et de licence en tête du .h ; décision de l'utilisateur (Q-ORG5-9) |
| R9 |
Délai : alpha le 2026-10-18 |
V-min seule dans l'alpha, 3.1 |
| R10 |
Faux sentiment de preuve : tout le comportement est lu par désassemblage, jamais vu en jeu |
J1 obligatoire avant toute mention « conforme à l'auteur » |
4.3 Lectures MCP / jeton UE manquantes (non lancées)
| # |
Lecture |
Ce qu'elle trancherait |
| L-M1 |
MCP list_toolsets puis describe_toolset filtré sur les noms contenant widget, umg ou user_widget (pas de description complète, lp-mcp § 1 règle 6) |
si l'arbre de widgets et la valeur par défaut d'une map sont créables par MCP : seul point qui rend les options A et C réalistes |
| L-M2 |
MCP ObjectTools.get_properties sur /Game/BPs/GI.Default__GI_C (CurrentTags, SexPersons, Cursor, PlayerCharacter, SexOn) et /Game/BPs/Person.Default__Person_C (Sex_OrgasmCounts, isPlayer, Name_First) — forme déjà utilisée : STG-B1-IMPL.md:41 |
types des propriétés (texte ou chaîne, réel float ou double) ; facultative : l'IMPL les gère par CastField et les journalise |
| L-M3 |
MCP BlueprintTools.get_node_infos sur K2Node_CustomEvent_87 et K2Node_CallFunction_1005 de Person, puis find_node_types pour le nœud NotifyOrgasm |
seulement pour H2 (I4) : broches, type_id |
| L-M4 |
commandlet LPDumpWidgetTree -BP=Cursor (éditeur fermé, lp-commandlets) |
seulement pour A et C : où placer ScrollBonuses dans notre arbre de Cursor (nos SexExclusives, ActionBox, BondageBox existent, grep -a -c 10 / 5 / 7 ; ScrollBonuses, TextBlock_0 : 0) |
| L-J1 |
essai en jeu de J1 (7.7 à 7.9) |
effet réel : fréquence des récompenses, tags de CurrentTags à l'orgasme, texte du nombre |
| L-S1 |
lecture non faite par manque d'intérêt pour B : propriétaire du son ui_positive du bouton BonusReward (style de bouton), arbre de widgets de Cursor de B |
apparence uniquement |
4.4 Questions (utilisateur / orchestrateur)
| # |
Question |
Recommandation |
| Q-ORG5-1 |
La version minimale (application automatique de la première récompense retenue, sans grille) convient-elle pour l'alpha, ou ne rien mettre dans l'alpha ? |
oui, V-min ; la grille (V-1) seulement si J1 PASS le 16 |
| Q-ORG5-2 |
Option B (C++ autonome) ou A / C (identique à l'auteur, exige L-M1) ? |
B |
| Q-ORG5-3 |
Nombre de récompenses : 3 (code du build 2023.04) ou 5 (journal 5.26) ? |
3 (le code fait foi) |
| Q-ORG5-4 |
Récompenses pour toute personne qui jouit (comme l'auteur, PNJ compris) ou pour le joueur seulement ? |
comme l'auteur ; attractiontoplayer reste réservée aux PNJ intéressés par le joueur |
| Q-ORG5-5 |
Valeur par défaut de bDisabled dans l'alpha (faux = fonction active) ; case de réglage avant l'alpha (V-2) ou ini seulement ? |
faux ; ini seulement |
| Q-ORG5-6 |
Accroche H1 (sondage) ou H2 (nœud dans GiveOrgasmReward, touche Person) ; que fera ORG4 : Person::Cum ou GiveOrgasmReward seul ? |
H1 pour l'alpha ; H2 après, selon ORG4 |
| Q-ORG5-7 |
Position du panneau (V-1) : à droite au centre (hypothèse), près du menu d'actions, ailleurs ? Retrait en fin de scène (écart voulu) ou boutons conservés comme l'auteur ? |
droite, centre ; retrait en fin de scène |
| Q-ORG5-8 |
Affichage du texte d'en-tête et des trois cas de E8 (textes de l'auteur en anglais, à garder tels quels ?) |
oui, tels quels |
| Q-ORG5-9 |
Licence : reconstruire le comportement lu dans le build de l'auteur (MIT, Licenses\Vinfamy_License.txt:1) est-il accepté, avec mention d'origine ? |
oui, avec commentaire d'origine |
| Q-ORG5-10 |
Garder le désassembleur Kismet (3 scripts du scratchpad de session) : le ranger dans Tools\ (lecture seule, utile à toute lecture de build cuit) ? |
oui, par une fiche d'outillage |
5. Interdits
- Version minimale : aucun asset modifié (ni
GI, Person, Room, Cursor, GameSettings, MainMenu, SettingCheckbox) ; aucun champ ajouté à GameSettings.sav ; le bonus ancien (OrgasmIrBoost, mood, attractiontoplayer) reste intact.
- Pas de création de widget, d'objet UMG ni d'
AddToViewport dans la pile de l'événement Cum ; pas de destruction d'un widget dans son propre gestionnaire de clic.
- Pas de
ProcessEvent sans FindFunction valide, sans paramètres initialisés puis détruits ; pas d'accès à une personne sans IsValid.
- Pas de contournement de garde : une propriété ou une fonction introuvable = avertissement unique et abandon, jamais de repli silencieux.
- Pas de
delete_node ni de type_id improvisé (H2) ; pas de commit par l'agent (le gardien) ; build et commandlets seulement sous jeton UE, éditeur fermé.
- Aucune ligne de la grille d'un autre lot, aucun contenu de jeu (noms, textes) dans un skill ou un message de commit public (
lp-paths).
6. Valeurs moteur lues dans le moteur installé
| Valeur |
Source |
Établi |
FCeil prend un double et rend un int32 ; MapRangeClamped prend et rend des double ; Subtract_DoubleDouble, Multiply_DoubleDouble |
D:\Game\Launcher\Engine\UE_5.8\Engine\Source\Runtime\Engine\Classes\Kismet\KismetMathLibrary.h:796, :836, :551, :555 |
oui |
RetriggerableDelay(WorldContext, float Duration, FLatentActionInfo), latent |
…\Kismet\KismetSystemLibrary.h:700-701 |
signature oui, remplacement du délai non relu |
GameViewportClient::AddViewportWidgetContent(TSharedRef<SWidget>, int32 ZOrder) et RemoveViewportWidgetContent |
…\Engine\GameViewportClient.h:258, :265 |
oui |
EX_JumpIfNot = « Goto if not expression » (saute quand la condition est fausse) ; EX_Context, EX_VirtualFunction, EX_CallMath, EX_SwitchValue, EX_TextConst : formats d'instruction |
D:\Game\Launcher\Engine\UE_4.27\Engine\Source\Runtime\CoreUObject\Public\UObject\Script.h:173 ; …\ScriptSerialization.h:150-557 (moteur 4.27 le plus proche du 4.20 de l'auteur ; contrôle : décodage exact jusqu'à EX_EndOfScript et cibles de saut toutes sur un début d'instruction, annexe A) |
oui |
FText::AsNumber / formatage par défaut des flottants (nombre de décimales) |
recherche de MaximumFractionalDigits dans Core\Public\Internationalization\FastDecimalFormat.h : aucune occurrence ; non lu ailleurs |
incertain : à lire à l'IMPL (Text.h, FastDecimalFormat.h voisins) avant de fixer l'attendu « 1.1 » |
7. Critères de VAL (commande → attendu ; « attendu » écrit avant tout lancement)
| # |
Fiche |
Commande ou lecture |
Attendu |
| 7.1 |
V1 |
git status --porcelain -- Content Source Config (jeu) comparé à l'état d'entrée (10 M, 4 ?? au 2026-10-14) |
seules deux lignes ?? de plus : Source/LifePlay/LPBonusRewardSubsystem.h et .cpp ; aucun M de plus |
| 7.2 |
V1 |
.\Tools\Build.ps1 (éditeur fermé) puis .\Tools\Build.ps1 -FromLog <journal> |
code de sortie 0 ; module LifePlay recompilé ; 0 erreur ; 0 avertissement C4996 nouveau sur les deux fichiers |
| 7.3 |
V1 |
Grep des clés dans le .cpp : motifs des 20 clés de 1.2 |
20 clés, 20 listes de tags identiques à 1.2 (relecture ligne à ligne) |
| 7.4 |
V1 |
lecture du .cpp contre 1.3 et 2.4 |
ordre des opérations de RewardChange identique ; Pick : 10 candidates, max 3, Overlaps avec drapeau vrai, règle attractiontoplayer ; aucun widget créé dans V-min |
| 7.5 |
V1 |
.\Tools\LogStats.ps1 -Latest <journal de démarrage> -Pattern 'Bonus : contrôle formule' |
1 ligne contrôle formule OK ; 0 ligne Error du sous-système |
| 7.6 |
V1 |
CompileAllBlueprints éditeur fermé ; LPTestStringCompat |
0 erreur /Game/ ; 3120 / 0 / 60 (aucun Blueprint modifié, valeurs de référence du lot) |
| 7.7 |
J1 |
scène avec le joueur jusqu'à un orgasme, journal avec -ScriptStackOnWarnings ; LogStats -Pattern 'Bonus :' |
par orgasme : 1 ligne orgasme de, puis soit 1 ligne <stat> <±valeur> soit aucune récompense éligible ; la valeur suit 1.3 pour le x journalisé |
| 7.8 |
J1 |
même journal, motifs Accessed None et PersonCumming |
0 occurrence nouvelle par rapport au journal de référence du lot |
| 7.9 |
J1 |
ini bDisabled=True, nouvel orgasme |
1 ligne désactivé ; 0 ligne de récompense ; la ligne mood du bonus ancien est toujours là |
| 7.10 |
V2 / J2 (V-1) |
clic sur un bouton |
1 ModifyStat, panneau retiré au tick suivant, 3 boutons au plus, 0 plantage ; clic hors panneau : les actions du jeu répondent |
Annexe A. Commandes et lectures (CART 2), comptes bruts
Aucun caractère de redirection dans les commandes ; B, O comme dans les sigles. <S> = scratchpad de session.
- Format du bytecode :
Read de UE_4.27\…\ScriptSerialization.h (574 lignes) et Script.h:150-300.
- Liste des fonctions de
Cursor : python -I <S>/kdis.py B/UI/Cursor.uasset B/UI/Cursor.uexp list → total=122954 names=703 exports=764 imports=293 ue=136556 ; ExecuteUbergraph_Cursor size=7504 uexp_off=6522 ; PopulateBonusRewards size=86 uexp_off=14414.
- Talon :
… kdbg.py B/UI/Cursor.uasset B/UI/Cursor.uexp PopulateBonusRewards 0 99999999 300 → 5 instructions, 14470 v:ExecuteUbergraph_Cursor(10856).
- Corps :
… kdbg.py … ExecuteUbergraph_Cursor 7000 9300 230 → q=7122 end=14014 tail=12 mem=10864 decoded=370 last_p=14014 err=None ; jumps=66 sur debut=66 (les 66 cibles de saut tombent sur un début d'instruction : le décodage est cohérent).
- Appel dans Person :
… kdbg.py B/BPs/Person.uasset B/BPs/Person.uexp ExecuteUbergraph_Person 20700 21700 420 → decoded=5164 … err=None, jumps=911 sur debut=911.
- Table :
python -I <S>/strs.py B/UI/Cursor.uexp 4620 6420 3 → 20 clés et leurs tags (offsets de 1.2).
BonusReward : … kdis.py B/UI/BonusReward.uasset B/UI/BonusReward.uexp list → 3 fonctions ; kdbg.py … ExecuteUbergraph_BonusReward → decoded=8 ; Get_RewardText_Text_0 → decoded=27, texte {stat} {sign}{change}. Get_TextBlock_0_Text_0 → decoded=19.
- Utilisateurs des noms :
… kall.py B/UI/Cursor.uasset B/UI/Cursor.uexp 'ScrollBonuses|lastCum|countBR|BonusReward|statTags' 120 → fonctions=45 decodees=45 correspondances=15 (13 dans l'ubergraph, 2 dans Get_TextBlock_0_Text_0). grep -r -l -a -E "ScrollBonuses|BonusReward_C|PopulateBonusRewards" B/BPs B/UI --include=*.uasset → Person.uasset, BonusReward.uasset, Cursor.uasset.
DisableBonus : … kall.py sur BPs/GI, BPs/GameSettings, UI/MainMenu, UI/SettingCheckbox avec le motif DisableBonus → GI fonctions=609 decodees=609 correspondances=2 (:866870, :869178) ; GameSettings fonctions=0 ; MainMenu fonctions=62 decodees=62 correspondances=0 ; SettingCheckbox fonctions=5 decodees=5 correspondances=2 (:1921, :13472). Get_SexExclusives_Visibility_0 → decoded=6.
GI.Overlaps et GI.IsInterestedIn du build : kdbg.py B/BPs/GI.uasset B/BPs/GI.uexp Overlaps (decoded=32, jumps=8 sur debut=8) et IsInterestedIn (decoded=20, jumps=6 sur debut=6) ; nos fonctions : L6f-G:19622-19673 (Overlaps, 14 nœuds, paramètres Array1, Array2, IfEmptyThenTrue) et :23421 (IsInterestedIn, 28 nœuds) ; noms dans O\BPs\GI.uasset (grep -a -c -F) : Overlaps 5, IsInterestedIn 11, Cursor 10, CurrentTags 1, PlayerCharacter 1, SexOn 1, SexPersons 33, PersonCumming 1. Tags dans O\BPs\GI.uasset (grep -a -o -w -F <mot> | wc -l) : Penetration 396, Foreplay 158, Cum 33, Anal 215, Titfuck 3, Boobjob 4, Cow 54, Cowgirl 204, Doggy 182, Doggystyle 11, Handjob 80, RubPussy 18, FingerPussy 9, Missionary 148, Oral 236, Blowjob 173, Cunnilingus 19, LickPussy 37, LickAss 4, Rimjob 20, ReverseCow 2, ReverseCowgirl 56, Aggressive 79, AggressiveFM 31, Spooning 19, Sidefuck 19, Spoon 5, Toys 30, Dildo 14, Vibrator 12, Tribadism 2, Scissor 12, Scissoring 2, Vaginal 327. Noms dans O\BPs\Person.uasset : Sex_OrgasmCounts 1, isPlayer 1, Name_First 1, ModifyStat 51, QueryStat 18, GiveOrgasmReward 2, OrgasmIrBoost 2. O\UI\Cursor.uasset : ScrollBonuses 0, TextBlock_0 0, PopulateBonusRewards 0, lastCum 0, SexExclusives 10, ActionBox 5, BondageBox 7.
- Formule :
python -I <S>/calc.py → table de 1.3 (double et float32 identiques). Sortie recopiée : 0 → 2.0 ; 10 → 1.9 ; 25 → 1.6 ; 50 → 1.1 ; 75 → 0.6 ; 90 → 0.3 ; 95, 99, 100, 120 → 0.2 ; −30 → 1.5.
- Journal de l'auteur :
Read D:\XxX\LifePlay_2023_04_Stable_64bit\Docs\Change_Logs.txt lignes 1-46 (:34 option 5.27 et plantages, :39 « 5 bonus rewards »).
- Dépôt :
git -C "D:/Game/LifePlay-master 5.8" status --porcelain -- Content Source Config → M : Content/BPs/GI.uasset, Person.uasset, Room.uasset, Source/LifePlay/LPDebugSubsystem.cpp/.h, LPDirectControlSubsystem.cpp/.h, LPOutdoorRoomSubsystem.cpp/.h, LifePlay.cpp ; ?? : LPCameraModeSubsystem.cpp/.h, LPSaveRelaunch.cpp/.h ; rc=0. git log --oneline -3 : tête 0745917.
- Précédents C++ : Grep de
FindFunction|ProcessEvent|AddViewportWidgetContent|… dans Source\LifePlay (lignes citées en 2.1) ; LifePlay.Build.cs:38 (Slate, SlateCore, UMG).
- Build de référence : Grep de
Total execution time dans STE-H3d_Build_20261013-124425.txt → ligne 10 : 18.56 seconds ; ligne 7 : toolchain 14.50.35739.
- Licence :
Read Licenses\Vinfamy_License.txt → ligne 1 : « … are under MIT ».
- Contrôle du livrable : fins de ligne (
tr -cd '\r' | wc -c → 0 CR), aucun nom d'utilisateur ni C:\Users (Grep → 0).
Désassembleur (méthode) : en-tête .uasset UE 4.20 lu à la main (variante 104 octets par export, 28 octets par import, noms avec 4 octets de hachage) ; le bytecode d'une fonction commence après 8 octets de tailles (mémoire, disque) ; EX_ décodés d'après ScriptSerialization.h 4.27 ; pointeurs de propriété ou d'objet = 4 octets sur disque, noms de fonction virtuelle = 8 octets sur disque et 12 en mémoire (c'est l'hypothèse qui rend toutes les cibles de saut cohérentes : 66 / 66, 911 / 911, 13 / 13 sur FilterActions, avec 8 octets : 2 sur 13). Les offsets d'instruction (m…) sont ceux de la mémoire, les autres ceux du .uexp.
Annexe B. Établi / estimé / incertain
- Établi : tout E1 à E10 (bytecode décodé, cohérence des sauts contrôlée) ; la table de 1.2 ; la formule et ses 21 valeurs ;
DisableBonus : sémantique, stockage, interface chez l'auteur ; absence chez nous de ScrollBonuses, PopulateBonusRewards, lastCum dans Cursor ; présence chez nous de Cursor dans GI, de Overlaps, IsInterestedIn, QueryStat, ModifyStat, Sex_OrgasmCounts ; précédents C++ cités ; licence MIT de la copie Licenses ; état git du 2026-10-14.
- Estimé : la grille s'ajoute au bonus ancien (ordre des instructions, confirmé par le saut
:21262) ; RetriggerableDelay remplace le délai en cours ; types des propriétés lues par réflexion (CurrentTags tableau de chaînes, Sex_OrgasmCounts entier, Name_First texte ou chaîne) ; WhoIsInterested = Person ; tags d'animation = mots présents dans GI ; tous les tours, durées et nombres de nœuds ; la pratique « ne pas détruire un widget dans son gestionnaire » (suspicion, non prouvée comme cause des plantages) ; faisabilité d'ici le 2026-10-18.
- Incertain : comportement en jeu (rien n'a été lancé) ; capacité du MCP à créer des widgets ou à fixer la valeur par défaut d'une map (L-M1) ; apparence exacte et position du panneau de l'auteur (arbre de widgets de
Cursor non lu) ; formatage de « 1.1 » par FText (section 6) ; ce que fera ORG4 (SPEC absente) ; son ui_positive ; effet réel des tags de position sur la fréquence des récompenses.
Tours : 38 / 55 (deux Write du livrable, contrôles et compte rendu compris ; le premier Write portait deux comptes erronés — scripts et exécutions — corrigés ici)
Constats
- F-ORG10 : le nombre de récompenses est 3 dans le code (
Cursor.uexp:8607), pas 5 (Change_Logs.txt:39, version 5.26) : le journal de l'auteur est antérieur au build 2023.04 ; corrige AUD § 9.1 et § 9.11 (L14 « origine du nombre 5 » résolu).
- F-ORG11 : la valeur à stat = 100 est 0,2 (pas 0,1 ni « 0,1 ou 0,2 »,
AUD § 9.5) ; mesuré en double et en float32.
- F-ORG12 :
DisableBonus vrai garde le bonus ancien et supprime seulement la grille (L15 résolu, AUD § 9.3 et § 9.7 : « incertain » devient établi).
- F-ORG13 : les deux lignes « prone_to_orgasm -1.1 » et « fitness +1.1 » des captures sont bien deux boutons proposés (
AUD § 9.4) : elles partagent les tags {Penetration, Foreplay, Cum}, et la valeur 1,1 correspond à x vers 50 (1.3).
- F-ORG14 : le bonus ancien et la grille sont indépendants : on peut livrer le tirage sans toucher
GiveOrgasmReward (accroche H1).
- F-ORG15 : un désassembleur Kismet de build cuit UE 4.20 existe maintenant (3 scripts Python de lecture seule dans le scratchpad de session) ; il décode 100 % des fonctions des assets lus (
Cursor 45 / 45, GI 609 / 609, MainMenu 62 / 62, SettingCheckbox 5 / 5, ubergraph de Person 5 164 instructions) ; proposition : le ranger dans Tools\ (Q-ORG5-10), ce qui lèverait la limite « aucun lecteur de Kismet cuit » de AUD § 9.11 L14.
- À verser :
lp-commandlets (section à créer « Lire un build cuit ») : cohérence de lecture = toutes les cibles de saut sur un début d'instruction ; FName 12 octets en mémoire, pointeurs 4 octets sur disque ; l'EventGraph d'un événement personnalisé est un talon ExecuteUbergraph_X(entrée) et le corps est dans l'ubergraph. sk-protocol § 7 : python -I <fichier du scratchpad> n'a jamais été refusé par le crochet (20 exécutions), seuls python -c et les heredocs le sont.
- Fichiers modifiés par cette fiche : le présent livrable seulement (deux Write, le second corrigeant le premier ; fins de ligne et noms d'utilisateur contrôlés sur le premier, texte inchangé hors les trois corrections).
- Fichiers à commiter :
A D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE\STE-ORG5-SPEC.md (dépôt du jeu, branche ue5.8 ; .md suivi sous etat/).
Décisions de l'utilisateur (2026-10-14, session STE)
- Q-ORG5-1 : version minimale pour l'alpha (tirage comme l'auteur, application automatique de la première récompense, sans grille) ; grille V-1 seulement si J1 PASS le 16.
- Q-ORG5-2 : option B, C++ autonome. Q-ORG5-3 : 3 récompenses (le code fait foi). Q-ORG5-4 : toute personne qui jouit, PNJ compris, comme l'auteur. Q-ORG5-9 : licence MIT acceptée, origine et licence citées en tête du
.h.
- Orchestrateur : Q-ORG5-5 =
bDisabled faux, ini seulement ; Q-ORG5-6 = H1 (sondage) pour l'alpha. Note : le bonus d'ORG4 à Endsex appelle GiveOrgasmReward sans incrémenter Sex_OrgasmCounts : H1 ne le verra pas (R7), accepté pour l'alpha.
Règle commune ORG4 / ORG5 (Big Boss, 2026-10-14)
- Pour un même orgasme, une personne reçoit au plus une fois le bonus de base (
GiveOrgasmReward) et au plus une fois les récompenses ORG5 (3 au plus) ; le cumul base + ORG5 est voulu, le même bonus deux fois non.
- Orgasme réel (
Person::Cum, jauge à 100 ou choix « Cum on … ») : GiveOrgasmReward une fois (chemin existant) ; ORG5 une fois, déclenché par l'incrément de Sex_OrgasmCounts (accroche H1).
Endsex (O4c) : GiveOrgasmReward une fois par participant éligible (homme > 90, femme = 100), sans Person::Cum : Sex_OrgasmCounts inchangé, donc pas de récompense ORG5 à Endsex ; un participant qui vient de jouir a sa jauge remise à 0 par Cum et n'est pas éligible : pas de second bonus de base.
- Toute IMPL qui change l'un de ces déclencheurs relit cette règle et la VAL la contrôle (V6 : un orgasme = 1 marqueur de base + au plus 1 ligne ORG5 par personne).