Binding of Isaac: Rebirth Wiki
Advertisement

Ceci est une analyse de la manière dont le jeu génère aléatoirement les différentes caractéristiques d' Character Eden icon Éden. Notez que cette analyse fut réalisée par BLouBLue sur la version v1.05 (pré-Afterbirth) et la version 1.06.T1 (Afterbirth+). L'analyse pour la version 1.7.9b (Repentance) a été réalisée par SarvaTathagata.

Lancement[ | ]

Quand le jeu est lancé, la principale chose à savoir est que celui-ci dérive un tas de sous-graines qui sont utilisées par les instances RNG dédiées aux objets, babioles, ressources, monstres, générations des étages et à la gestion des Personnage Personnages.

Cela permet de jouer une partie légèrement différemment, tout en ayant les mêmes objets aux mêmes endroits (pour la plupart, ce n'est pas tout à fait vrai).

Une sous-graine de "personnage" spécifique est utilisée pour la génération d' Character Eden icon Éden. Cette instance RNG est utilisée durant deux phases:

  1. La génération des Cœur Cœurs, des ressources et attributs, avant l'initialisation du niveau;
  2. Le choix aléatoire des Carte Cartes, des Pilule Pilules, des babioles et des objets, après l'initialisation du niveau.

Il revient à la sous-graine du Personnage Personnage avant chaque phase. Cela signifie que les mêmes nombres aléatoires peuvent sortir du RNG dans le même ordre pour les deux phases.

Cœurs[ | ]

Les Cœur Cœurs sont la première chose à être générée. Le jeu essaye de son mieux pour donner 3 cœurs entiers, Cœur Rouge coeurs rouges et Cœur d'Âme coeurs d'âme confondus:

  1. Le jeu choisit aléatoirement x = 0 à 3 Cœur Rouge coeurs rouges.
  2. Il choisit aléatoirement entre 0 et (3 - x) Cœur d'Âme coeurs d'âme.
  3. Si aucun cœur rouge n'est choisi pendant la première étape, le jeu garantit au joueur au moins 2 cœurs d'âme.

Il ne peut y avoir aucun Cœur Noir coeur noir lors de cette phase. Les objets donnés par la suite peuvent dépasser ces limites.

Clés, bombes et pièces[ | ]

Éden a 1 chance sur 3 de commencer avec soit des Clé Clés, des Bombe Bombes ou des Pièce Pièces. Si cette chance a été accordée, voici les résultats possibles:

  1. Éden commence avec 1 Clé Clé;
  2. Éden commence avec 1 ou 2 Bombe Bombes;
  3. Éden commence avec 1 à 5 Pièce Pièces.

Les objets données par la suite peuvent octroyer des ressources supplémentaires, amenant le total au-dessus de ces limites.

La chance de commencer avec une ressource est calculée comme suit:

// rand(min,max) renvoie un entier aléatoire entre min (inclus) et max (exclus)
if(rand(0, 3) == 0)
{ // 1 chance sur 3 que le joueur ait une ressource
    tmp = rand(0, 3); // soit 0, 1 ou 2
    if(tmp == 0)
        donne 1 clé
    else if(tmp == 1)
        donne 1 + rand(0,2) bombes
    else
        donne 1 + rand(0,5) pièces
}

Attributs[ | ]

Les attributs sont basés sur les attributs de base d'Isaac. Un modificateur (valeur décimale) est aléatoirement choisi pour chacun des 6 attributs :

Attribut Intervalle de modification d'Éden
dégâts -1.00 à +1.00 nets
vitesse -0.15 à +0.15
débit Retiré dans Repentance -0.75 à +0.75 Ajouté dans Repentance -0.5 à +0.75
hauteur des larmes -5.00 à +5.00
vitesse des larmes -0.25 à +0.25
chance -1.00 à +1.00

Voici à quoi ressemble l'initialisation des attributs:

// personnageRng.Random() renvoie une valeur décimale entre 0.0 et 1.0
Joueur->modificateurAttributDégâts         = (personnageRng.Random() * 2.0f) + -1.0f;
Joueur->modificateurAttributVitesse        = (personnageRng.Random() * 0.3f) + -0.15f;
Joueur->modificateurAttributCadenceTir     = (personnageRng.Random() * 1.5f) + -0.75f;
Joueur->modificateurAttributPortée         = (personnageRng.Random() * 10.0f) + -5.0f;
Joueur->modificateurAttributVitesseLarmes  = (personnageRng.Random() * 0.5f) + -0.25f;
Joueur->modificateurAttributChance         = (personnageRng.Random() * 2.0f) + -1.0f;

Objets de poche[ | ]

Les Pilule Pilules, Carte Cartes, babioles et objets sont choisis après la génération de l'étage. Deux phases se produisent:

  1. Donne au joueur une chance d'avoir soit une pilule, soit une carte, soit une babiole;
  2. Tente de choisir 1 objet activable et 1 objet passif.

Donc, lors de la consommation d'un jeton d'Éden, il y a:

  • 1 chance sur 3 d'obtenir une babiole;
  • 1 chance sur 6 d'obtenir une Pilules;
  • 1 chance sur 6 d'obtenir une carte;
  • 1 chance sur 3 de ne rien obtenir.

Ces options sont mutuellement exclusives. On ne peut obtenir une babiole et une carte ou pilule. Voici à quoi ressemble la génération:

if(personnageRng.Random(3) > 0) { // 2 chances sur 3 d'obtenir une pilule, une carte ou rien
    if(personnageRng.Random(2) > 0) { // 2 chances sur 3 * 1 chance sur 2 de ne rien obtenir
        ne donne rien
    }
    else { // 2 chances sur 3 * 1 chance sur 2 chance d'obtenir une pilule ou une carte
        if(personnageRng.Random(2) > 0) { // 1 chance sur 3 * 1 chance sur 2 de générer une pilule
            donne une pilule aléatoire
        }
        else { // 1 chance sur 3 * 1 chance sur 2 de générer une carte
            donne une carte aléatoire
        }
    }
}
else { // 1 chance sur 3 d'obtenir une babiole
    donne une babiole aléatoire
}

En savoir plus sur la manière dont les objets de chaque type sont sélectionnés:

  • Les couleurs et effets de Pilule Pilules sont mélangés en se basant sur une sous-graine dérivée de la graine principale. 9 ou Ajouté dans Afterbirth13 effets de pilules sont sélectionnés et affectés à aléatoirement chacune des couleurs. S'il en a eu la chance, Character Eden icon Éden obtient aléatoirement l'une de ces pilules.
  • Les babioles sont choisies aléatoirement parmi les babioles débloquées. Il y a 32/Ajouté dans Afterbirth †64 relancements aléatoires, et un autre en cas d'échec. Le jeu peut abandonner si le joueur n'a débloqué aucune babiole.
  • Character Eden icon Éden ne peut pas commencer avec l'une des cartes/runes suivantes:
    • Toute rune ou Ajouté dans Repentance pierre d'Âme,
    • 2 of Trèfle, 2 of Carreau, 2 of Pique, 2 of Cœur, Joker,
    • Ajouté dans Afterbirth † As de Trèfle, As de Carreau, As de Pique, As de Cœur,
    • Ajouté dans Repentance Dame de Cœur.
  • 2 sets de cartes sont créés:
    • Un set de cartes spéciales contenant:
      • Carte Chaos, Carte de Crédit, Carte des Règles, Une Carte Limite Limite et Roi Suicidaire,
      • Ajouté dans Afterbirth Carte Chance, Carte ?, Fragment de Dé, Appel d'Urgence,
      • Ajouté dans Afterbirth † Carte Sacrée, Croissance Colossale, Rappel Ancestral, Marche Temporelle,
      • Ajouté dans Repentance Clé Brisée, Dernière Carte
    • Un set global contenant toutes les autres cartes exceptées celles étant interdites,
    • Éden a 1 chance sur 25 d'obtenir aléatoirement une carte du set spécial et a 24 chances sur 25 d'en obtenir une du set global.
    • Ajouté dans Repentance Chaque carte d'arcane majeur a 1 chance sur 7 d'être remplacée par sa version renversée.

Retiré dans Repentance Voici comment est réalisée la sélection des cartes, en pseudo-code:

// estRunesPermis et estCartesSpecialesPermis sont mis sur false lors de l'initialisation d'Éden.
// Les ID des cartes peuvent être trouvés dans les fichiers xml du jeu
// rngCarte.Random(min,max) renvoie un entier aléatoire entre min (inclus) et max (exclus)
// rngCarte.Random(max) renvoie un entier aléatoire entre 0 (inclus) et max (exclus, donc max-1 est la limite supérieure)
if(rngCarte.Random(25) > 0) // 24 chances sur 25 
{
    if(rngCarte.Random(10) || !estRunesPermis ) 
    {
        bool tmp = (rngCarte.Random(5) != 0) || !estCartesSpecialesPermis ;
        if(tmp == false) 
        {
            carte_premiere = CARD_2_OF_CLUBS;
            carte_derniere = CARD_JOKER;
        }
        else
        {
            carte_premiere = CARD_0_THE_FOOL;
            carte_derniere = CARD_XXI_THE_WORLD;
        }
    }
    else
    {
        carte_premiere = RUNE_DESTRUCTION_HAGALAZ;
        carte_derniere = RUNE_RESISTANCE_ALGIZ; // RUNE_BLACK dans AB+
    }
}
else 
{
    carte_premiere = CARD_CHAOS_CARD;
    carte_derniere = CARD_SUICIDE_KING; // CARD_ERA_WALK dans AB+
}

return rngCarte.Random(carte_premiere , carte_derniere + 1);

Ajouté dans Repentance Voici comment est réalisée la sélection des cartes dans Repentance:

if (rngCarte.next() % 25 == 0) {
	// Les cartes spéciales de Carte Chaos à Marche Temporelle, avec 2 cartes en plus dans Repentance.
	int carte = (int)(rngCarte.next() % 15) + 42;
	
	if(carte == 55){carte=78;} // Clé Brisée
	if(carte == 56){carte=80;} // Dernière Carte
		
	return carte;
}

// La vérification des runes et des cartes à jouer est retirée dans Repentance.

// Les cartes normales de 0 - Le Mat à XXI - Le Monde
int carte = (int)(cardRng.next() % 22) + 1;

// Les cartes d'arcanes majeures renversées, ajouté dans Repentance
if(cardRng.next() % 7 == 0){
	carte += 55;
}
	
return carte;

Objets[ | ]

Le jeu tente 100 fois de remplir l'emplacement d'objet activable et un pour un objet passif. À chaque essai, il choisit aléatoirement un ID d'objet entre 1 et 346/Ajouté dans Afterbirth †552/Ajouté dans Repentance732.

Retiré dans RepentanceIl y a quelques ID d'objets désactivés qui demandent au jeu de re-choisir un nouvel ID et de passer à la prochaine tentative:

  • #43: "Pills here!", un objet activable ne faisant rien et ressemblant à une pilule.
    • Cela pourrait être un clin d'œil dans le code, référençant le "Pills Here!" quand le joueur trouve une pilule non-identifiée dans le jeu Flash.
  • #59: "Tarot Card", un objet passif ressemblant à une carte et ne faisant rien.
    • Ajouté dans Repentance Cet ID appartient désormais au Livre de Bélial du Droit d'Aînesse de Judas.
  • #61: Littéralement rien, et n'est pas défini dans items.xml.
  • #235: Non disponible
  • #238: Premier Fragment de Clé Premier Fragment de Clé
  • #239: Second Fragment de Clé Second Fragment de Clé
  • #263: Retiré dans RepentanceNon disponible
  • #550: Ajouté dans Afterbirth †Pelle Brisée Pelle Brisée (morceau #1)
  • #551: Ajouté dans Afterbirth †Pelle Brisée Pelle Brisée (morceau #2)
  • #552: Ajouté dans Afterbirth †Pelle de Maman Pelle de Maman

Ajouté dans Repentance Un objet sera désactivé uniquement s'il a la balise noeden.

Le premier candidat valide (objet débloqué) pour l'emplacement actif ou passif est sélectionné et ne peut pas être écrasé par les tentatives ultérieures (il y aura 100 tentatives peu importe le résultat).

Ces objets sont donnés au joueur après les 100 tentatives, que les deux emplacements aient été remplis ou non.

Par conséquent, Éden peut commencer pour le mieux avec 1 objet activable et 1 objet passif. Il est hautement improbable qu'une graine existante puisse donner à Éden seulement 1 ou aucun objet.

Comme rien n'ajoute de poids à certains objets spécifiquement, chaque combo d'objets a probablement environ Retiré dans Repentance0.005% / Ajouté dans Repentance0.001% de chance d'être obtenu. Matériel de test: 1000 graines avec Éden.

C# Code[ | ]

Retiré dans RepentanceLe code pour déterminer les objets d'Éden pour une graine donnée. Il manque le code pour les babioles, pilules et statistiques.

void Main()
{
	var seeds = new List<uint>();
	for(uint i = 0; i < uint.MaxValue; i++)
	{
		var startSeed = (uint)i;
		var dropSeed = CalculatePlayerSeed(startSeed);
		var items = CalculateEdenItems(dropSeed);

		if (items.Active == 186 && (items.Passive == 276 || items.Passive == 108 || items.Passive == 301) && items.Card == 5)
		{
			seeds.Add(startSeed);	
			SeedToString(startSeed).Dump();
		}
		if (i % 100000000 == 0)
			(":" + i).Dump();
	}
	seeds.Select(s => SeedToString(s)).ToArray().Dump();
}

//ItemCount impacte l'objet choisi par la RNG même si Éden ne peut pas commencer avec un objet qui a un ID supérieur à 552/732 dans Repentance
public static EdenItems CalculateEdenItems(uint dropSeed, int itemCount = 552)
{
	var rng = new Rng(dropSeed, 0x1, 0x5, 0x13);
	
	var trinket = 0;
	var card = 0;
	var pill = 0;
	var hearts = 0;
	var soulHearts = 0;	
	if ((rng.Next() % 3) == 0) 
	{
		// Babiole
	}
	else if ((rng.Next() & 1) == 0) 
	{
		if ((rng.Next() & 1) == 0) 
		{
			card = GetCard(rng.Next());
		}
		else
		{
			// Pilule
			var pillSeed = rng.Next();
		}
	}
	
	var activeId = 0;
	var passiveId = 0;
	for (var i = 0; i < 100; i++) 
	{
		int itemId = (int)(rng.Next() % itemCount) + 1;
		
		// Liste des objets bannis
		if (itemId > 552)
			continue;
		switch(itemId){
			case 0x3B:
			case 0xEB:
			case 0x107:
			case 0x2b:
			case 0x3d:
			case 0xee:
			case 0xef:
			case 0x226:
			case 0x227:
			case 0x228:
				continue;
			default:
				break;
		}
		
		var itemType = ItemConfig[itemId];
		if (itemType == ItemType.Active)
		{
			activeId = activeId != 0 ? activeId : itemId;
		} 
		else if (itemType == ItemType.Passive || itemType == ItemType.Familiar) 
		{
			passiveId = passiveId != 0 ? passiveId : itemId;
		}
		if (activeId != 0 && passiveId != 0)
			break;

	}
	
	//Les coeurs rouges et d'âme sont traités dans Player::Init
	var healthRng = new Rng(dropSeed, 0x1, 0x5, 0x13);
	var halfHearts = (int)healthRng.Next() & 3;
	hearts = halfHearts * 2;
	soulHearts = ((int)healthRng.Next() % (4 - halfHearts)) * 2;
	if (hearts == 0 && soulHearts < 4)
	 	soulHearts = 4;
		
	
	
	return new EdenItems(hearts, soulHearts, activeId, passiveId, trinket, card, pill);
}
public static int GetCard(uint seed, bool playing = false)
{
	var cardRng = new Rng(seed, 0x5, 0x9, 0x7);
	if (cardRng.Next() % 25 == 0) {
		return (int)(cardRng.Next() % 13) + 42;
	}
	if (cardRng.Next() % 10 == 0)
	{
		// Rune
	}
	if (cardRng.Next() % 5 == 0 && playing)
	{
		// Carte à jouer
		return (int)(cardRng.Next() % 9) + 23;
	}
	return (int)(cardRng.Next() % 22) + 1;
}


public static uint CalculatePlayerInitSeed(uint startSeed)
{
	var startRng = new Rng(startSeed, 0x3, 0x17, 0x19);
	// Graine d'étage
	for (var i = 0; i < 0xD; i++)
		startRng.Next();
	return startRng.Next(); //Seeds::PlayerInitSeed
}

public static uint CalculatePlayerSeed(uint startSeed)
{
	var playerInitSeed = CalculatePlayerInitSeed(startSeed);

	// Ceci se produit dans Player::Init
	var playerInitRng = new Rng(playerInitSeed, 0x1, 0xB, 0x10);
	// Graine de CollectiblesRNG
	playerInitRng.Next();
	playerInitRng.Next();
	playerInitRng.Next();
	// Graine de CardsRNG
	playerInitRng.Next();
	
	return playerInitRng.Next(); // Entity::DropSeed
}

public class EdenItems
{
	public int Hearts;
	public int SoulHearts;
	public int Active;
	public int Passive;
	public int Trinket;
	public int Card;
	public int Pill;
	public EdenItems(int hearts, int soulHearts, int active, int passive, int trinket, int card, int pill) 
	{
		Hearts = hearts;
		SoulHearts = soulHearts;
		Active = active;
		Passive = passive;
		Trinket = trinket;
		Card = card;
		Pill = pill;
	}
}

static string SeedToString(uint num)
{
	const string chars = "ABCDEFGHJKLMNPQRSTWXYZ01234V6789";
	byte x = 0;
	var tnum = num;
	while (tnum != 0)
	{
		x += ((byte)tnum);
		x += (byte)(x + (x >> 7));
		tnum >>= 5;
	}
	num ^= 0x0FEF7FFD;
	tnum = (num) << 8 | x;

	var ret = new char[8];
	for (int i = 0; i < 6; i++)
	{
		ret[i] = chars[(int)(num >> (27 - (i * 5)) & 0x1F)];
	}
	ret[6] = chars[(int)(tnum >> 5 & 0x1F)];
	ret[7] = chars[(int)(tnum & 0x1F)];

	return new string(ret);
}

public class Rng
{
	public uint Seed;
	public int Shift1;
	public int Shift2;
	public int Shift3;
	public uint Next()
	{
		var num = Seed;
		num ^= num >> Shift1;
		num ^= num << Shift2;
		num ^= num >> Shift3;
		Seed = num;
		return num;
	}
	
	public Rng(uint seed, int s1, int s2, int s3) {
		this.Seed = seed;
		Shift1 = s1;
		Shift2 = s2;
		Shift3 = s3;
	}
};

public enum ItemType {
	Null = 0,
	Passive = 1,
	Trinket = 2,
	Active = 3,
	Familiar = 4,
}

public static ItemType[] ItemConfig = GetItemConfig();
public static ItemType[] GetItemConfig() {
	var itemConfig = new ItemType[553];
	return itemConfig;
}

Le code complet peut être trouvé ici ou pour la version Repentance ici


Advertisement