16.3: Funkcje do obsługi broni i mikstur

Cele lekcji

Po zakończeniu tej lekcji…

  • Nie nauczysz się niczego nowego. Dokończysz program, korzystając z wiedzy, którą już dysponujesz.

 

Stworzymy teraz funkcje, z których gracz będzie korzystał podczas walki z potworami.

Postać może wykonać dwie akcje (poza ucieczką z walki): użyć broni na potworze lub użyć mikstury leczniczej na sobie – jeśli ma ją w ekwipunku.

Poniżej znajduje się pseudokod obu funkcji:

Użycie funkcji broni

  • Pobierz aktualnie wybraną broń z formantu ComboBox cboWeapons
  • Określ obrażenia zadane potworowi przez gracza
  • Pomniejsz punkty CurrentHitPoints zgodnie z obrażeniami
    • Wyświetl komunikat
  • Jeśli potwór jest martwy (ma zero punktów wytrzymałości)
    • Wyświetl komunikat o zwycięstwie
    • Przydziel graczowi punkty doświadczenia za zabicie potwora
      • Wyświetl komunikat
    • Przydziel graczowi złoto za zabicie potwora
      • Wyświetl komunikat
    • Przydziel łupy za potwora
      • Wyświetl komunikat dla każdego łupu
      • Dodaj odpowiednie przedmioty do ekwipunku gracza
    • Odśwież dane gracza w interfejsie użytkownika
      • Złoto i punkty doświadczenia ExperiencePoints
      • Ekwipunek i formanty ComboBox
    • „Przenieś” gracza do bieżącej lokacji
      • Spowoduje to uzdrowienie gracza i stworzenie nowego potwora
  • Jeśli potwór nadal żyje
    • Określ obrażenia zadane potworowi
    • Wyświetl komunikat
    • Odejmij punkty obrażeń od aktualnych punktów obrażeń CurrentHitPoints
      • Odśwież dane gracza w interfejsie użytkownika
    • Jeśli gracz jest martwy (ma zero punktów wytrzymałości)
      • Wyświetl komunikat
      • „Przenieś” gracza do lokacji początkowej

 

Używanie funkcji eliksiru

  • Uzyskaj aktualnie wybrany eliksir z formantu cboPotions ComboBox
  • Zwiększ liczbę punktów wytrzymałości CurrentHitPoints gracza
    • Liczba punktów CurrentHitPoints nie może być większa od maksymalnej liczby punktów wytrzymałości MaximumHitPoints
  • Usuń miksturę z ekwipunku gracza
  • Wyświetl komunikat
  • Tura ataku potwora
    • Określ obrażenia zadane potworowi
    • Wyświetl komunikat
    • Odejmij punkty obrażeń od aktualnych punktów obrażeń CurrentHitPoints
      • Odśwież dane gracza w interfejsie użytkownika
    • Jeśli gracz jest martwy (ma zero punktów wytrzymałości)
      • Wyświetl komunikat
      • „Przenieś” gracza do lokacji początkowej
  • Odśwież dane gracza w interfejsie użytkownika

 

Są to znacznie prostsze funkcje niż funkcja MoveTo().

Będziemy mogli korzystać z niektórych mniejszych funkcji, które stworzyliśmy podczas refaktoryzacji, na przykład z funkcji AddItemToInventory() w klasie Player, jeśli gracz pokona potwora i otrzyma łupy.

 

Dodanie funkcji walk z potworami

 

Etap 1: Uruchom aplikację Visual Studio i otwórz swoje rozwiązanie.

 

Etap 2: Aby rozpocząć pracę z kodem interfejsu użytkownika, prawym przyciskiem myszy kliknij formularz SuperAdventure.cs w projekcie SuperAdventure.

Aby dodać możliwość używania broni i mikstur podczas walk, można dodać poniższy kod lub zastąpić kod SuperAdventure.cs, używając poniższego kodu: https://gist.github.com/ScottLilly/b20787650f2ab2a78362

 

Do funkcji btnUseWeapon_Click dodaj:

private void btnUseWeapon_Click(object sender, EventArgs e)
{
    // Get the currently selected weapon from the cboWeapons ComboBox
    Weapon currentWeapon = (Weapon)cboWeapons.SelectedItem;

    // Determine the amount of damage to do to the monster
    int damageToMonster = RandomNumberGenerator.NumberBetween(currentWeapon.MinimumDamage, currentWeapon.MaximumDamage);

    // Apply the damage to the monster's CurrentHitPoints
    _currentMonster.CurrentHitPoints -= damageToMonster;

    // Display message
    rtbMessages.Text += "You hit the " + _currentMonster.Name + " for " + damageToMonster.ToString() + " points." + Environment.NewLine;

    // Check if the monster is dead
    if(_currentMonster.CurrentHitPoints <= 0)
    {
        // Monster is dead
        rtbMessages.Text += Environment.NewLine;
        rtbMessages.Text += "You defeated the " + _currentMonster.Name + Environment.NewLine;

        // Give player experience points for killing the monster
        _player.ExperiencePoints += _currentMonster.RewardExperiencePoints;
        rtbMessages.Text += "You receive " + _currentMonster.RewardExperiencePoints.ToString() + " experience points" + Environment.NewLine;

        // Give player gold for killing the monster
        _player.Gold += _currentMonster.RewardGold;
        rtbMessages.Text += "You receive " + _currentMonster.RewardGold.ToString() + " gold" + Environment.NewLine;

        // Get random loot items from the monster
        List<InventoryItem> lootedItems = new List<InventoryItem>();

        // Add items to the lootedItems list, comparing a random number to the drop percentage
        foreach(LootItem lootItem in _currentMonster.LootTable)
        {
            if(RandomNumberGenerator.NumberBetween(1, 100) <= lootItem.DropPercentage)
            {
                lootedItems.Add(new InventoryItem(lootItem.Details, 1));
            }
        }

        // If no items were randomly selected, then add the default loot item(s).
        if(lootedItems.Count == 0)
        {
            foreach(LootItem lootItem in _currentMonster.LootTable)
            {
                if(lootItem.IsDefaultItem)
                {
                    lootedItems.Add(new InventoryItem(lootItem.Details, 1));
                }
            }
        }

        // Add the looted items to the player's inventory
        foreach(InventoryItem inventoryItem in lootedItems)
        {
            _player.AddItemToInventory(inventoryItem.Details);

            if(inventoryItem.Quantity == 1)
            {
                rtbMessages.Text += "You loot " + inventoryItem.Quantity.ToString() + " " + inventoryItem.Details.Name +Environment.NewLine;
            }
            else
            {
                rtbMessages.Text += "You loot " + inventoryItem.Quantity.ToString() + " " + inventoryItem.Details.NamePlural + Environment.NewLine;
            }
        }

        // Refresh player information and inventory controls
        lblHitPoints.Text = _player.CurrentHitPoints.ToString();
        lblGold.Text = _player.Gold.ToString();
        lblExperience.Text = _player.ExperiencePoints.ToString();
        lblLevel.Text = _player.Level.ToString();

        UpdateInventoryListInUI();
        UpdateWeaponListInUI();
        UpdatePotionListInUI();

        // Add a blank line to the messages box, just for appearance.
        rtbMessages.Text += Environment.NewLine;

        // Move player to current location (to heal player and create a new monster to fight)
        MoveTo(_player.CurrentLocation);
    }
    else
    {
        // Monster is still alive

        // Determine the amount of damage the monster does to the player
        int damageToPlayer = RandomNumberGenerator.NumberBetween(0, _currentMonster.MaximumDamage);

        // Display message
        rtbMessages.Text += "The " + _currentMonster.Name + " did " + damageToPlayer.ToString() + " points of damage." + Environment.NewLine;

        // Subtract damage from player
        _player.CurrentHitPoints -= damageToPlayer;

        // Refresh player data in UI
        lblHitPoints.Text = _player.CurrentHitPoints.ToString();

        if(_player.CurrentHitPoints <= 0)
        {
            // Display message
            rtbMessages.Text += "The " + _currentMonster.Name + " killed you." + Environment.NewLine;

            // Move player to "Home"
            MoveTo(World.LocationByID(World.LOCATION_ID_HOME));
        }
    }
}

 

Następnie do funkcji btnUsePotion_Click dodaj:

private void btnUsePotion_Click(object sender, EventArgs e)
{
    // Get the currently selected potion from the combobox
    HealingPotion potion = (HealingPotion)cboPotions.SelectedItem;

    // Add healing amount to the player's current hit points
    _player.CurrentHitPoints = (_player.CurrentHitPoints + potion.AmountToHeal);

    // CurrentHitPoints cannot exceed player's MaximumHitPoints
    if(_player.CurrentHitPoints > _player.MaximumHitPoints)
    {
        _player.CurrentHitPoints = _player.MaximumHitPoints;
    }

    // Remove the potion from the player's inventory
    foreach(InventoryItem ii in _player.Inventory)
    {
        if(ii.Details.ID == potion.ID)
        {
            ii.Quantity--;
            break;
        }
    }

    // Display message
    rtbMessages.Text += "You drink a " + potion.Name + Environment.NewLine;

    // Monster gets their turn to attack

    // Determine the amount of damage the monster does to the player
    int damageToPlayer = RandomNumberGenerator.NumberBetween(0, _currentMonster.MaximumDamage);

    // Display message
    rtbMessages.Text += "The " + _currentMonster.Name + " did " + damageToPlayer.ToString() + " points of damage." + Environment.NewLine;

    // Subtract damage from player
    _player.CurrentHitPoints -= damageToPlayer;

    if(_player.CurrentHitPoints <= 0)
    {
        // Display message
        rtbMessages.Text += "The " + _currentMonster.Name + " killed you." + Environment.NewLine;

        // Move player to "Home"
        MoveTo(World.LocationByID(World.LOCATION_ID_HOME));
    }

    // Refresh player data in UI
    lblHitPoints.Text = _player.CurrentHitPoints.ToString();
    UpdateInventoryListInUI();
    UpdatePotionListInUI();
}

 

W tych dwóch funkcjach nie pojawia się nic nowego. Dodawane są po prostu kolejne pętle if i foreach do obsługi działań gracza podczas walki.

 

Podsumowanie

Teraz gra już działa, a gracz może poruszać się po świecie, wykonywać zadania, walczyć z potworami, otrzymywać łupy i wykonywać zadania.

Te nowe funkcje można jeszcze refaktoryzować, ponieważ są długie i wykonują kilka czynności, ale to już zadanie dla Ciebie.

 

Łącza do tej lekcji

Kod źródłowy w serwisie GitHub

Kod źródłowy w serwisie Dropbox

Leave a Reply

Your email address will not be published. Required fields are marked *