From 9a4e7c44d76b5552f88a32fc3b2b34e20fa25cea Mon Sep 17 00:00:00 2001 From: Rudolf Zambory Date: Thu, 12 Jun 2025 13:00:33 +0200 Subject: [PATCH] aaaauto --- du8/Makefile | 22 ++ du8/README.md | 106 ++++++++++ du8/asteroids | Bin 0 -> 26904 bytes du8/game.c | 563 ++++++++++++++++++++++++++++++++++++++++++++++++++ du8/game.h | 37 ++++ du8/game.o | Bin 0 -> 14696 bytes du8/main.c | 39 ++++ du8/main.o | Bin 0 -> 2464 bytes du8/world.c | 73 +++++++ du8/world.h | 21 ++ du8/world.o | Bin 0 -> 6592 bytes 11 files changed, 861 insertions(+) create mode 100644 du8/Makefile create mode 100644 du8/README.md create mode 100755 du8/asteroids create mode 100644 du8/game.c create mode 100644 du8/game.h create mode 100644 du8/game.o create mode 100644 du8/main.c create mode 100644 du8/main.o create mode 100644 du8/world.c create mode 100644 du8/world.h create mode 100644 du8/world.o diff --git a/du8/Makefile b/du8/Makefile new file mode 100644 index 0000000..51c416e --- /dev/null +++ b/du8/Makefile @@ -0,0 +1,22 @@ +CC = gcc +CFLAGS = -Wall -Wextra -pedantic -std=c99 +LIBS = -lncurses -lm +TARGET = asteroids +OBJS = main.o game.o world.o + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) $(CFLAGS) -o $(TARGET) $(OBJS) $(LIBS) + +main.o: main.c game.h world.h + $(CC) $(CFLAGS) -c main.c + +game.o: game.c game.h world.h + $(CC) $(CFLAGS) -c game.c + +world.o: world.c world.h + $(CC) $(CFLAGS) -c world.c + +clean: + rm -f $(TARGET) $(OBJS) diff --git a/du8/README.md b/du8/README.md new file mode 100644 index 0000000..7a8a810 --- /dev/null +++ b/du8/README.md @@ -0,0 +1,106 @@ +======================================= + Dokumentácia hry: Ultimate Asteroids +======================================= + + +Predstavenie Hry +------------------ + +Ultimate Asteroids je dynamická 2D vesmírna strieľačka, ktorá berie to najlepšie z klasických arkádových hier ako Space Invaders. Ako pilot osamelej vesmírnej lode je vašou úlohou prežiť nápor neustále prichádzajúcich vĺn nepriateľov a nakoniec sa postaviť tvárou v tvár mocnej Materskej lodi vo finálnom súboji. + +Hra ponúka svieži pohľad na známy žáner a obsahuje: + +* Menu s voľbou obtiažnosti, ktorá priamo ovplyvňuje rýchlosť a agresivitu nepriateľov. +* Štyri unikátne typy nepriateľov s odlišným správaním a odolnosťou. +* Dynamický combo systém, ktorý vás odmení za rýchle a presné zničenie protivníkov. +* Taktické bariéry, ktoré dočasne blokujú strely a menia dynamiku boja. +* Epický súboj s finálnym bossom, ktorý preverí všetky vaše schopnosti svojimi unikátnymi útočnými vzormi. + + +Preklad a Spustenie +--------------------- + +Hra je napísaná v jazyku C a pre zobrazenie a interakciu využíva knižnicu 'ncurses' (prostredníctvom dodanej knižnice 'world'). + +Požiadavky: +* Prekladač 'gcc' +* Nástroj 'make' +* Knižnica 'ncurses' (na serveri sigma je štandardne dostupná) + +Postup prekladu: +1. Umiestnite všetky súbory ('Makefile', 'main.c', 'game.c', 'game.h', 'world.c', 'world.h') do jedného adresára. +2. V termináli prejdite do tohto adresára. +3. Spustite príkaz 'make'. Tento príkaz automaticky skompiluje všetky súbory a vytvorí finálny spustiteľný súbor s názvom 'asteroids'. + + +Spustenie hry: +Hru spustíte z terminálu nasledujúcim príkazom: + + ./asteroids + + +Návod na Hranie +----------------- + +Cieľ hry: +Vaším hlavným cieľom je prežiť čo najdlhšie, nahrať čo najvyššie skóre a po uplynutí približne jednej minúty poraziť finálneho bossa – Materskú loď. + +Ovládanie: +* Šípka vľavo: Pohyb lode doľava. +* Šípka vpravo: Pohyb lode doprava. +* Medzerník: Vystrelenie projektilu. +* q: Okamžité ukončenie hry. + +Herné mechaniky: + +Životy: Začínate s 5 životmi. Život stratíte, ak sa vaša loď zrazí s nepriateľom, alebo ak nepriateľ preletí cez spodný okraj obrazovky a unikne vám. + +Nepriatelia: V hre narazíte na 4 typy nepriateľov: +* 'v' Asteroid: Základný nepriateľ. Letí priamo dole a nepredstavuje veľkú hrozbu osamote. +* 'S' Stíhač: Nevyspytateľný protivník, ktorý sa pohybuje v sínusových vlnách, čo ho robí ťažkým cieľom. +* 'O' Tank: Odolný nepriateľ, ktorý vydrží až dva zásahy, kým ho zničíte. +* '*' Mína: Pasívna hrozba, ktorá po určitom čase sama zmizne. + +Bariéry <===>: V náhodných intervaloch sa na obrazovke objavujú dočasné bariéry. Slúžia ako štít, ktorý blokuje vaše strely, ale pozor – nepriatelia cez ne môžu bez problémov prejsť! + +Combo systém: Za každého nepriateľa zničeného v rýchlom slede sa vám zvyšuje násobič skóre (Combo: x2, x3, ...). Ako špeciálny bonus, po dosiahnutí COMBA x10, vaša loď získa dočasný ŠTÍT, ktorý ju ochráni pred jedným zásahom alebo koliziou. + +Boss fight: Po uplynutí stanoveného času sa na obrazovke zobrazí varovanie a začne súboj s Materskou loďou. Boss sa pohybuje zo strany na stranu a strieda dva útočné vzory: streľbu a vypúšťanie nepriateľov. + +Koniec hry: +* Prehra: Hra končí, keď počet vašich životov klesne na nulu. +* Výhra: Hra končí vaším triumfom po úspešnom zničení Materskej lode. + + +Popis Implementácie +---------------------- + + +Najdôležitejšie štruktúry ('game.h'): +* 'StavHry': Centrálna štruktúra, ktorá drží kompletný stav celej hry – obsahuje polia pre všetky dynamické objekty, informácie o hráčovi a bossovi, a tiež premenné riadiace stav hry ('stav_programu'), skóre, životy a rôzne časovače. +* 'Nepriatel': Reprezentuje jedného nepriateľa. Okrem pozície obsahuje aj 'typ', 'hp' (životy) a 'farbu'. +* 'Boss': Unikátna štruktúra pre finálneho bossa, ktorá si pamätá jeho životy, aktuálny útočný vzor ('aktualny_vzor') a časovače. + +Kľúčové funkcie: +* 'main()' ('main.c'): Vstupný bod programu. Jeho jediná úloha je odovzdať riadenie knižnici 'world' a poskytnúť jej tri kľúčové "callback" funkcie. +* 'world_event()' ('main.c'): Centrálny dispečer udalostí, ktorý reaguje na stlačenie klávesy alebo uplynutie času a volá ďalšie funkcie. +* 'aktualizuj_stav()' ('game.c'): "Srdce" hernej slučky. Volá sa v pravidelných intervaloch a zabezpečuje všetku hernú logiku. +* 'vykresli_stav()' ('game.c'): Zodpovedá za kompletné vykreslenie všetkého na obrazovku. + + + + +Modifikácia knižnice 'world' +------------------------------ + +Pôvodná knižnica 'world' mala definície funkcií umiestnené priamo v hlavičkovom súbore 'world.h', čo spôsobovalo chyby pri kompilácii ("redefinition of function"). + +Riešenie: +Knižnica bola vylepšená tak, aby hlavičkový súbor 'world.h' obsahoval iba DEKLARÁCIE funkcií a zdrojový súbor 'world.c' obsahoval ich IMPLEMENTÁCIU .Týmto sa zabezpečila bezchybná kompilácia. + + +Použité Zdroje +----------------- + +* Základná knižnica 'world': https://github.com/hladek/world (poskytnutá v rámci zadania) +* Inšpirácia: žáner "shoot 'em up" ako Space Invaders a Galaga. diff --git a/du8/asteroids b/du8/asteroids new file mode 100755 index 0000000000000000000000000000000000000000..2e18ac69bfeaa42e807cdcf33ad57287a4340b2c GIT binary patch literal 26904 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 literal 0 HcmV?d00001 diff --git a/du8/game.c b/du8/game.c new file mode 100644 index 0000000..f2cf2c3 --- /dev/null +++ b/du8/game.c @@ -0,0 +1,563 @@ +#include +#include +#include +#include +#include "game.h" + +// --- Deklaracie funkcii --- +void spusti_hru(StavHry *stav); +void vytvor_nepriatela(StavHry *stav); +void vytvor_barieru(StavHry *stav); +void vystrel(StavHry *stav); +void inicializuj_bossa(StavHry *stav); +void spracuj_logiku_bossa(StavHry *stav); + +// Grafika pre bossa +const char *boss_logo[] = { "<[O|O|O]>", "//---\\\\" }; + + +/********************************************************** +* 1. CAST : VSTUP A ZACIATOCNE FUNKCIE/PARAMETRE ATD. +**********************************************************/ + +/* + * Spracovanie vstupu - stlacenie klaves + * stav -> Ukazovatel na aktualny stav hry + * klavesa -> cod stlacenej klavesy + */ +void spracuj_vstup(StavHry *stav, int klavesa) +{ + // ovladanie v hlavnom menu + if (stav->stav_programu == V_MENU) { + switch (klavesa) { + case KEY_UP: + stav->menu_vyber--; + if (stav->menu_vyber < 0) stav->menu_vyber = 2; + break; + case KEY_DOWN: + stav->menu_vyber++; + if (stav->menu_vyber > 2) stav->menu_vyber = 0; + break; + case KEY_ENTER: + case '\n': + case '\r': + case ' ': + stav->obtiaznost = (Obtiaznost)stav->menu_vyber; + spusti_hru(stav); + break; + } + } + // ovladanie pocas hry a BOSS fightu + else if (stav->stav_programu == HRAJE_SA || stav->stav_programu == BOSS_SOUBOJ) { + switch (klavesa) { + case KEY_LEFT: + stav->hrac.data.x -= 2; + break; + case KEY_RIGHT: + stav->hrac.data.x += 2; + break; + case ' ': + vystrel(stav); + break; + } + // teleport na druhu sstranu + if (stav->hrac.data.x < 0) { + stav->hrac.data.x = stav->sirka_obrazovky - 1; + } + if (stav->hrac.data.x >= stav->sirka_obrazovky) { + stav->hrac.data.x = 0; + } + } +} + +/* + * Rozbehnutie zakladnych veci pri prvom spusteni + */ +void inicializuj_hru(StavHry *stav, int sirka, int vyska) { + stav->sirka_obrazovky = sirka; + stav->vyska_obrazovky = vyska; + stav->stav_programu = V_MENU; + stav->menu_vyber = 0; + game_speed(80); // rychlost hry (menej je rychlejsie) +} + +/* + * Spusti novu hru a resetuje udaje zo starej + */ +void spusti_hru(StavHry *stav) { + // Ulozenie nastaveni, ktore sa maju zachovat (sirka, vyska, obtiaznost) + int sirka = stav->sirka_obrazovky; + int vyska = stav->vyska_obrazovky; + Obtiaznost obt = stav->obtiaznost; + + // odstranenie starych udajov z memory + memset(stav, 0, sizeof(StavHry)); + + // zakladne veci pre hru + stav->sirka_obrazovky = sirka; + stav->vyska_obrazovky = vyska; + stav->obtiaznost = obt; + stav->stav_programu = HRAJE_SA; + stav->zivoty = 5; + + // startovna pozicia mojej lode + stav->hrac.data.x = stav->sirka_obrazovky / 2.0; + stav->hrac.data.y = stav->vyska_obrazovky - 2; + stav->hrac.data.aktivny = 1; + + // spawner barier + switch (stav->obtiaznost) { + case LAHKA: stav->bariera_spawn_casovac = 60; break; + case STREDNA: stav->bariera_spawn_casovac = 50; break; + case TAZKA: stav->bariera_spawn_casovac = 40; break; + } +} + + +/********************************************************** +* 2. CAST : VYTVARANIE LODI +**********************************************************/ + +//vytvaranie enemy ldoi +void vytvor_nepriatela(StavHry *stav) { + for (int i = 0; i < MAX_NEPRIATELIA; i++) { + if (!stav->nepriatelia[i].data.aktivny) { + Nepriatel *n = &stav->nepriatelia[i]; + n->data.aktivny = 1; + n->data.x = rand() % stav->sirka_obrazovky; + n->data.y = 0; + n->pociatocne_x = n->data.x; // Pre sinusovy pohyb + + // randomne urcovanie typu lode + int typ_roll = rand() % 100; + if (typ_roll < 60) n->typ = TYP_ASTEROID; + else if (typ_roll < 85) n->typ = TYP_STIHAC; + else if (typ_roll < 95) n->typ = TYP_TANK; + else n->typ = TYP_MINA; + + // Nastavenie vlastnosti podla typu + switch (n->typ) { + case TYP_ASTEROID: n->hp = 1; n->farba = COLOR_WHITE; break; + case TYP_STIHAC: n->hp = 2; n->farba = COLOR_CYAN; break; + case TYP_TANK: n->hp = 5; n->farba = COLOR_GREEN; break; + case TYP_MINA: n->hp = 3; n->farba = COLOR_RED; n->casovac = 50; break; + } + + // rychlost podla obtiaznosti + float rychlost_mod = 1.0f; + if (stav->obtiaznost == STREDNA) rychlost_mod = 1.2f; + if (stav->obtiaznost == TAZKA) rychlost_mod = 1.6f; + n->data.rychlost_y = (0.08 + (rand() % 10) / 80.0) * rychlost_mod; + return; + } + } +} + +/* + * Vytvaranie barier + */ +void vytvor_barieru(StavHry *stav) { + for (int i = 0; i < MAX_BARIERY; i++) { + if (!stav->bariery[i].data.aktivny) { + Bariera *b = &stav->bariery[i]; + b->data.aktivny = 1; + b->data.x = rand() % (stav->sirka_obrazovky - 5); // 5 je sirka baqriery, toto nemenit + b->data.y = rand() % (stav->vyska_obrazovky - 10) + 5; // na y v strede + b->zivotnost = 25; + return; + } + } +} + +/* + * Vytvaranie strely + */ +void vystrel(StavHry *stav) { + for (int i = 0; i < MAX_STRELY; i++) { + if (!stav->strely_hrac[i].data.aktivny) { + Strela *s = &stav->strely_hrac[i]; + s->data.aktivny = 1; + s->data.x = stav->hrac.data.x; + s->data.y = stav->hrac.data.y - 1; + s->data.rychlost_y = -1; // ide hore :) + return; + } + } +} + +/** + * spawn bossa a priprava na bossfight + */ +void inicializuj_bossa(StavHry *stav) { + stav->stav_programu = BOSS_SOUBOJ; + // despawn enemy lodi + for (int i = 0; i < MAX_NEPRIATELIA; i++) { + stav->nepriatelia[i].data.aktivny = 0; + } + Boss *b = &stav->boss; + b->aktivny = 1; + b->hp = BOSS_HP; + b->data.x = stav->sirka_obrazovky / 2; + b->data.y = 5; + b->data.rychlost_x = 0.15; + b->smer_pohybu = 1; // 1 = doprava, -1 = dolava + b->aktualny_vzor = VZOR_SWEEP; + b->casovac_fazy = 400; // zmena utocneho vzoru + b->casovac_utoku = 30; // rychlost strielanie (mensie je rychlejsie) +} + + +/********************************************************** +* 3. CAST : AKTUALIZACIA LOGIKY +**********************************************************/ + +/** + * Aktualizovanie pozicie vsetkych veci na obrazovke + */ +void pohybuj_objektami(StavHry *stav) +{ + // Pohyb nepriatelov + for (int i = 0; i < MAX_NEPRIATELIA; i++) { + if (stav->nepriatelia[i].data.aktivny) { + Nepriatel *n = &stav->nepriatelia[i]; + + // vsetky enemy lode letia dole + n->data.y += n->data.rychlost_y; + + // Stihac ('S') - uhybne manevre + if (n->typ == TYP_STIHAC) { + n->data.x = n->pociatocne_x + sin(n->data.y * 0.1) * 15; + // teleport na druhu stranu ak pojde za okraj + if (n->data.x < 0) n->data.x = stav->sirka_obrazovky - 1; + if (n->data.x >= stav->sirka_obrazovky) n->data.x = 0; + } + + // Despawn ak prejde za spodny okraj + if (n->data.y > stav->vyska_obrazovky) { + n->data.aktivny = 0; + if (stav->stit_casovac <= 0) { // odcitanie len pri neaktivnom stite + stav->zivoty--; + } + } + } + } + + // Pohyb striel hraca + for (int i = 0; i < MAX_STRELY; i++) { + if (stav->strely_hrac[i].data.aktivny) { + stav->strely_hrac[i].data.y += stav->strely_hrac[i].data.rychlost_y; + if (stav->strely_hrac[i].data.y < 0) { + stav->strely_hrac[i].data.aktivny = 0; + } + } + } + + // Pohyb striel bossa + for (int i = 0; i < MAX_STRELY; i++) { + if (stav->strely_boss[i].data.aktivny) { + stav->strely_boss[i].data.y += stav->strely_boss[i].data.rychlost_y; + if (stav->strely_boss[i].data.y > stav->vyska_obrazovky) { + stav->strely_boss[i].data.aktivny = 0; + } + } + } + + // Pohyb bossa + if (stav->boss.aktivny) { + stav->boss.data.x += stav->boss.data.rychlost_x * stav->boss.smer_pohybu; + if (stav->boss.data.x < 5 || stav->boss.data.x > stav->sirka_obrazovky - 5) { + stav->boss.smer_pohybu *= -1; // Zmeni smer na okraji + } + } + + // casovac zmiznutia bariery + for (int i = 0; i < MAX_BARIERY; i++) { + if (stav->bariery[i].data.aktivny) { + stav->bariery[i].zivotnost--; + if (stav->bariery[i].zivotnost <= 0) { + stav->bariery[i].data.aktivny = 0; + } + } + } +} + +/** + * Spracovanie utokov bossa, meni jeho fazy a vytvara strely a nepriatelov. + */ +void spracuj_logiku_bossa(StavHry *stav) { + if (!stav->boss.aktivny) return; + + stav->boss.casovac_fazy--; + stav->boss.casovac_utoku--; + + // Zmena utocneho vzoru po uplynuti casu + if (stav->boss.casovac_fazy <= 0) { + stav->boss.aktualny_vzor = (BossAttackPattern)(rand() % 2); // random vyber + stav->boss.casovac_fazy = 300 + rand() % 200; + stav->boss.casovac_utoku = 0; // Okamzity utok po zmene fazy + } + + // zautocenie ak uplynul casovac utoku + if (stav->boss.casovac_utoku <= 0) { + switch (stav->boss.aktualny_vzor) { + case VZOR_SWEEP: // strelba pri pohybe + stav->boss.casovac_utoku = 60; + for (int i = 0; i < MAX_STRELY; i++) { + if (!stav->strely_boss[i].data.aktivny) { + Strela *s = &stav->strely_boss[i]; + s->data.aktivny = 1; + s->data.x = stav->boss.data.x; + s->data.y = stav->boss.data.y + 2; + s->data.rychlost_y = 0.4; + return; + } + } + break; + case VZOR_MINIONS: // vytvaranie lodi + stav->boss.casovac_utoku = 120; + vytvor_nepriatela(stav); + vytvor_nepriatela(stav); + break; + } + } +} + +/** + * Oprava kolizii objektov + */ +void ries_kolizie(StavHry *stav) { + // Strely hraca vs Bariera + for (int i = 0; i < MAX_STRELY; i++) { + if (!stav->strely_hrac[i].data.aktivny) continue; + for (int j = 0; j < MAX_BARIERY; j++) { + if (!stav->bariery[j].data.aktivny) continue; + // zasiahla barieru? + if (fabs(stav->strely_hrac[i].data.y - stav->bariery[j].data.y) < 1 && + stav->strely_hrac[i].data.x >= stav->bariery[j].data.x && + stav->strely_hrac[i].data.x <= stav->bariery[j].data.x + 5) { + stav->strely_hrac[i].data.aktivny = 0; // Znicenie strely + break; + } + } + } + + // Strely hraca vs Enemy + for (int i = 0; i < MAX_STRELY; i++) { + if (!stav->strely_hrac[i].data.aktivny) continue; + for (int j = 0; j < MAX_NEPRIATELIA; j++) { + if (!stav->nepriatelia[j].data.aktivny) continue; + // Kontrola, ci strela zasiahla nepriatela + if (fabs(stav->strely_hrac[i].data.x - stav->nepriatelia[j].data.x) < 2 && + fabs(stav->strely_hrac[i].data.y - stav->nepriatelia[j].data.y) < 2) { + stav->strely_hrac[i].data.aktivny = 0; + stav->nepriatelia[j].hp--; + if (stav->nepriatelia[j].hp <= 0) { // Ak nepriatelovi klesne HP na 0 + stav->nepriatelia[j].data.aktivny = 0; + stav->skore += 10 * (1 + stav->combo_pocitadlo); + stav->combo_pocitadlo++; + stav->combo_casovac = 100; // Reset casovaca pre combo + } else { + stav->nepriatelia[j].farba = COLOR_YELLOW; // Vizuálna odozva na zásah + } + break; + } + } + } + + // Strely hraca vs Boss + if (stav->boss.aktivny) { + for (int i = 0; i < MAX_STRELY; i++) { + if (!stav->strely_hrac[i].data.aktivny) continue; + // kONTROLA ci strela hitla bossa + if (fabs(stav->strely_hrac[i].data.x - stav->boss.data.x) < 5 && + fabs(stav->strely_hrac[i].data.y - stav->boss.data.y) < 2) { + stav->strely_hrac[i].data.aktivny = 0; + stav->boss.hp--; + stav->skore += 50; + if (stav->boss.hp <= 0) { + stav->boss.aktivny = 0; + stav->stav_programu = KONIEC_HRY_VYHRA; + } + } + } + } + + // Kolizie s hracom ak nema stit + if (stav->stit_casovac <= 0) { + // Hrac vs Enemy strewtnutie + for (int i = 0; i < MAX_NEPRIATELIA; i++) { + if (stav->nepriatelia[i].data.aktivny && + fabs(stav->hrac.data.x - stav->nepriatelia[i].data.x) < 2 && + fabs(stav->hrac.data.y - stav->nepriatelia[i].data.y) < 2) { + stav->zivoty--; + stav->nepriatelia[i].data.aktivny = 0; + } + } + // Hrac vs strely bossa + for (int i = 0; i < MAX_STRELY; i++) { + if (stav->strely_boss[i].data.aktivny && + fabs(stav->hrac.data.x - stav->strely_boss[i].data.x) < 2 && + fabs(stav->hrac.data.y - stav->strely_boss[i].data.y) < 2) { + stav->zivoty--; + stav->strely_boss[i].data.aktivny = 0; + } + } + } +} + +/** + * !!!!!!!!!!!!!! Hlavna funkcia pre aktualizaciu logiky hry, volana v kazdom cykle. !!!!!!!!!!!!!!!!!!!!! + */ +void aktualizuj_stav(StavHry *stav) { + // V menu / na konci hry neaktualizovat + if (stav->stav_programu == V_MENU || stav->stav_programu == KONIEC_HRY_VYHRA || stav->stav_programu == KONIEC_HRY_PREHRA) { + return; + } + + // boss warning + if (stav->stav_programu == BOSS_VAROVANIE) { + stav->boss_varovanie_casovac--; + if (stav->boss_varovanie_casovac <= 0) { + inicializuj_bossa(stav); + } + return; + } + + stav->casovac_herneho_cyklu++; + + // Aktualizacia casovacov pre combo a stit + if (stav->combo_casovac > 0) stav->combo_casovac--; else stav->combo_pocitadlo = 0; + if (stav->stit_casovac > 0) stav->stit_casovac--; + + // Aktivacia stitu za combo + if (stav->combo_pocitadlo > 0 && stav->combo_pocitadlo % 10 == 0) { + stav->stit_casovac = 250; + stav->combo_pocitadlo++; // aby sa stit neaktivoval pre to iste combo + } + + pohybuj_objektami(stav); + ries_kolizie(stav); + + if (stav->stav_programu == HRAJE_SA) { + // spawn emeny teamu podla obtiaznosati + int spawn_sanca = (stav->obtiaznost == LAHKA) ? 3 : ((stav->obtiaznost == STREDNA) ? 5 : 8); + if (rand() % 100 < spawn_sanca) { + vytvor_nepriatela(stav); + } + + // Vytvaranie novych barier + stav->bariera_spawn_casovac--; + if (stav->bariera_spawn_casovac <= 0) { + vytvor_barieru(stav); + switch (stav->obtiaznost) { // Reset casovaca + case LAHKA: stav->bariera_spawn_casovac = 60; break; + case STREDNA: stav->bariera_spawn_casovac = 50; break; + case TAZKA: stav->bariera_spawn_casovac = 40; break; + } + } + + // Prechod do fazy varovania pred bossom + if (stav->casovac_herneho_cyklu >= CAS_DO_BOSSA && !stav->boss.aktivny) { + stav->stav_programu = BOSS_VAROVANIE; + stav->boss_varovanie_casovac = 150; + } + } + else if (stav->stav_programu == BOSS_SOUBOJ) { + spracuj_logiku_bossa(stav); + } + + // Kontrola prehry + if (stav->zivoty <= 0) { + stav->stav_programu = KONIEC_HRY_PREHRA; + } +} + + +/********************************************************** +* 4. CAST : VYKRESLENIE +**********************************************************/ + + +void vykresli_stav(StavHry *stav) { + clear_screen(); + + // Main menu + if (stav->stav_programu == V_MENU) { + set_message("ULTIMATE ASTEROIDS", stav->sirka_obrazovky / 2 - 10, stav->vyska_obrazovky / 2 - 4); + set_message("Vyber si obtiaznost:", stav->sirka_obrazovky / 2 - 10, stav->vyska_obrazovky / 2 - 2); + char t[3][20]; + sprintf(t[0], "%s Lahka", (stav->menu_vyber == 0) ? ">" : " "); + sprintf(t[1], "%s Stredna", (stav->menu_vyber == 1) ? ">" : " "); + sprintf(t[2], "%s Tazka", (stav->menu_vyber == 2) ? ">" : " "); + for (int i = 0; i < 3; i++) { + set_message(t[i], stav->sirka_obrazovky / 2 - 10, stav->vyska_obrazovky / 2 + i); + } + set_message("Ovladanie: Sipky, Enter", 1, stav->vyska_obrazovky - 2); + return; + } + + // Vyzor hraca + int hrac_farba = (stav->stit_casovac > 0) ? COLOR_CYAN : COLOR_YELLOW; + set_color_cell('^', (int)stav->hrac.data.x, (int)stav->hrac.data.y, hrac_farba, COLOR_BLACK); + + // Vyzor enemy lodi + for (int i = 0; i < MAX_NEPRIATELIA; i++) { + if (stav->nepriatelia[i].data.aktivny) { + char c = '?'; + switch (stav->nepriatelia[i].typ) { + case TYP_ASTEROID: c = 'v'; break; + case TYP_STIHAC: c = 'S'; break; + case TYP_TANK: c = 'O'; break; + case TYP_MINA: c = '*'; break; + } + set_color_cell(c, (int)stav->nepriatelia[i].data.x, (int)stav->nepriatelia[i].data.y, stav->nepriatelia[i].farba, COLOR_BLACK); + } + } + + // Vyzor striel hrac/boss + for (int i = 0; i < MAX_STRELY; i++) { + if (stav->strely_hrac[i].data.aktivny) { + set_color_cell('|', (int)stav->strely_hrac[i].data.x, (int)stav->strely_hrac[i].data.y, COLOR_RED, COLOR_BLACK); + } + if (stav->strely_boss[i].data.aktivny) { + set_color_cell('!', (int)stav->strely_boss[i].data.x, (int)stav->strely_boss[i].data.y, COLOR_MAGENTA, COLOR_BLACK); + } + } + + // Nakreslenie bariery + for (int i = 0; i < MAX_BARIERY; i++) { + if (stav->bariery[i].data.aktivny) { + set_message("<===>", (int)stav->bariery[i].data.x, (int)stav->bariery[i].data.y); + } + } + + // Nakreslenie bossa + if (stav->boss.aktivny) { + for (int y = 0; y < 2; y++) { + set_message(boss_logo[y], stav->boss.data.x - 5, stav->boss.data.y + y); + } + } + + // HUD + char ui_text[120]; + sprintf(ui_text, "Skore: %d | Zivoty: %d | Combo: x%d", stav->skore, stav->zivoty, 1 + stav->combo_pocitadlo); + set_message(ui_text, 1, 1); + + // Vypis HP pri BOSSFIGHTE + if (stav->stav_programu == BOSS_SOUBOJ && stav->boss.hp > 0) { + char boss_hp_text[20]; + sprintf(boss_hp_text, "BOSS HP: %d", stav->boss.hp); + set_message(boss_hp_text, stav->sirka_obrazovky / 2 - 5, 4); + } + + // Vypis sprav + if (stav->stav_programu == BOSS_VAROVANIE) { + set_message("!!! MATERSKA LOD PRICHAZA !!!", stav->sirka_obrazovky / 2 - 15, stav->vyska_obrazovky / 2); + } + if (stav->stav_programu == KONIEC_HRY_PREHRA) { + set_message("GAME OVER", stav->sirka_obrazovky / 2 - 5, stav->vyska_obrazovky / 2); + } + if (stav->stav_programu == KONIEC_HRY_VYHRA) { + set_message("!!! VITAZSTVO !!!", stav->sirka_obrazovky / 2 - 8, stav->vyska_obrazovky / 2); + } +} diff --git a/du8/game.h b/du8/game.h new file mode 100644 index 0000000..45792bd --- /dev/null +++ b/du8/game.h @@ -0,0 +1,37 @@ +#ifndef GAME_H_ +#define GAME_H_ + +#include "world.h" + +typedef enum { V_MENU, HRAJE_SA, BOSS_VAROVANIE, BOSS_SOUBOJ, KONIEC_HRY_PREHRA, KONIEC_HRY_VYHRA } StavProgramu; +typedef enum { LAHKA, STREDNA, TAZKA } Obtiaznost; +typedef enum { TYP_ASTEROID, TYP_STIHAC, TYP_TANK, TYP_MINA } TypNepriatela; +typedef enum { VZOR_SWEEP, VZOR_MINIONS } BossAttackPattern; +#define MAX_NEPRIATELIA 60 +#define MAX_STRELY 50 +#define MAX_BARIERY 15 +#define BOSS_HP 30 +#define CAS_DO_BOSSA 1200 + +typedef struct { double x, y, rychlost_x, rychlost_y; int aktivny; } PohybujuciObjekt; +typedef struct { PohybujuciObjekt data; } Strela; +typedef struct { PohybujuciObjekt data; TypNepriatela typ; int hp, farba, casovac; double pociatocne_x; } Nepriatel; +typedef struct { PohybujuciObjekt data; int zivotnost; } Bariera; +typedef struct { PohybujuciObjekt data; } Hrac; +typedef struct { int aktivny; PohybujuciObjekt data; int hp, smer_pohybu, casovac_utoku, casovac_fazy; BossAttackPattern aktualny_vzor; } Boss; + +typedef struct { + Hrac hrac; Nepriatel nepriatelia[MAX_NEPRIATELIA]; Strela strely_hrac[MAX_STRELY]; + Strela strely_boss[MAX_STRELY]; Bariera bariery[MAX_BARIERY]; Boss boss; + int skore, zivoty, casovac_herneho_cyklu, menu_vyber; + StavProgramu stav_programu; Obtiaznost obtiaznost; + int combo_pocitadlo, combo_casovac, stit_casovac, boss_varovanie_casovac, bariera_spawn_casovac; + int sirka_obrazovky, vyska_obrazovky; +} StavHry; + +void inicializuj_hru(StavHry *stav, int sirka, int vyska); +void spracuj_vstup(StavHry *stav, int klavesa); +void aktualizuj_stav(StavHry *stav); +void vykresli_stav(StavHry *stav); + +#endif diff --git a/du8/game.o b/du8/game.o new file mode 100644 index 0000000000000000000000000000000000000000..da610fc82ad6258f04a43873095c59fa12fc403b GIT binary patch literal 14696 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 literal 0 HcmV?d00001 diff --git a/du8/main.c b/du8/main.c new file mode 100644 index 0000000..3a39240 --- /dev/null +++ b/du8/main.c @@ -0,0 +1,39 @@ +#include +#include +#include "world.h" +#include "game.h" + +void* init_game() +{ + StavHry *stav = (StavHry*) malloc(sizeof(StavHry)); + if (stav == NULL) return NULL; + srand(time(NULL)); + return stav; +} + +void destroy_game(void* game) +{ + free(game); +} + +int world_event(struct event* event, void* game) +{ + StavHry *stav = (StavHry*) game; + + if (event->type == EVENT_START) { + inicializuj_hru(stav, event->width, event->height); + } else if (event->type == EVENT_KEY) { + if (event->key == 'q' || event->type == EVENT_ESC) return 1; + spracuj_vstup(stav, event->key); + } else if (event->type == EVENT_TIMEOUT) { + aktualizuj_stav(stav); + } + + vykresli_stav(stav); + return 0; +} + +int main() +{ + return start_world(init_game, world_event, destroy_game); +} diff --git a/du8/main.o b/du8/main.o new file mode 100644 index 0000000000000000000000000000000000000000..c8dbf6f7fafb577b237308c4e0c40972f6fb5941 GIT binary patch literal 2464 zcmb`I&ubJ(6vy9;qlucBC<<|1-9f^luxT<9a|oithFKetMT97bI@6hH&6xRRclDTr zM1^4&h9H~c9{dBmdh@0z?CQm%N6AG9#Dn5x5W#)l>Z(a?({m9YRM)G|`%%?ZudDCn z&i|H7BuGnwPSe&%Q=-C-Ej=sMEDh2CeHuFQdB$$Pvs>?npNH0y@yeT7i7td0-gGmJbUhORqPhz- zb@`gcf*)+h3)}7Iw$}dXYT*W4dqHQXr>D}#W@dw$2-2C1HDQg9Wdb?O+&yu^8lO0> zFr_%#FgK(<`}+(fiJpON;|AFuc9dAUNQs5v#G!${{xyE9ADN>;&ft;TGyG?AdT>XR z9e4=aDR7pb@X+>4TlTBqERXTf_T(e!fcRx_mN7iEy%fd+#R)b%MIXP$*|x=0AlACi z;PPE03-=|O=O6>@S5%HLh~uNokzePPd%-Nz!+%owU*{eo_lEmlxy9wb*n<~(@J0`Q zmpRrsq&`x)=ge9?{Hf}cYgUoUwX(?HbgC|cN~K;TQD)uuoLY%Wt}nd$VrahMxh~zQ zdzDh&ZMrpq$YR;4l$U~A`8h8jzu`GW)|Uep`dorzI+YEGB|2n^OFY06{PuPgQGSye`xSs27hbt-3IR%e8Au-wZB;7puvAo zoWDQnGx(^%cN*L>IKEZA&PgNxkipZeLy#X$OI9hG>pCq&xUR?h5w7cnEPt^ooLTOL z7xr^n^W2JK33ow|RdR$w)~xT7RjgO5r~|837p}#3&ln$QabAsY)&i^H)f=uS7Rizs z+`0S>50&;kB+W^%RmSf}rp?MH-(6}S)zG*hLUM>ZoMAQ`cApJEmb8jTtw2RBK}N!k ze&!xr-?IwSa%5i3qxcs#Am_Kn=WlqICuT!oU!fu1of^78n0Pt-sRs43%j7e}zJCO8@`> literal 0 HcmV?d00001 diff --git a/du8/world.c b/du8/world.c new file mode 100644 index 0000000..d1d6b3c --- /dev/null +++ b/du8/world.c @@ -0,0 +1,73 @@ +#include "world.h" +#include +#include +#include +#include +#include + +int TIMEOUT; + +void abort_game(const char* message) { endwin(); puts(message); exit(1); } + +void check_bounds(const char* source, int x, int y) { + char msg[200]; + if (x < 0 || x >= COLS) { sprintf(msg, "%s: width %d out of bounds (0,%d)", source, x, COLS); abort_game(msg); } + if (y < 0 || y >= LINES) { sprintf(msg, "%s: height %d out of bounds (0,%d)", source, y, LINES); abort_game(msg); } +} + +void clear_screen() { erase(); } +void game_speed(int value) { if (value < 0) abort_game("game_speed: negative"); TIMEOUT = value; } +void set_message(const char* message, int x, int y) { mvprintw(y, x, "%s", message); } +void set_cell(int character, int x, int y) { set_color_cell(character, x, y, COLOR_WHITE, COLOR_BLACK); } + +void set_color_cell(int character, int x, int y, short front_color, short back_color) { + check_bounds("set_color_cell", x, y); + if (has_colors()) { + int pair_id = front_color * 8 + back_color + 1; + attron(COLOR_PAIR(pair_id)); + mvaddch(y, x, character); + attroff(COLOR_PAIR(pair_id)); + } else { + mvaddch(y, x, character); + } +} + +int start_world(void* (*init_game)(), int (*world_event)(struct event* event, void* game), void (*destroy_game)(void* game)) { + srand(time(NULL)); + int r = 0; + TIMEOUT = 100; + if (initscr() == NULL) { puts("Curses Error."); return -1; } + noecho(); cbreak(); nodelay(stdscr, TRUE); keypad(stdscr, TRUE); curs_set(FALSE); + + if (has_colors()) { + start_color(); + for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) init_pair(i * 8 + j + 1, i, j); + } + void* game_state = NULL; + if (init_game != NULL) { game_state = init_game(); assert(game_state != NULL); } + + timeout(TIMEOUT); + struct event event; + memset(&event, 0, sizeof(struct event)); + event.height = LINES; event.width = COLS; event.type = EVENT_START; + + r = world_event(&event, game_state); + refresh(); + while (!r) { + memset(&event, 0, sizeof(struct event)); + event.height = LINES; event.width = COLS; + event.key = getch(); + if (event.key == ERR) event.type = EVENT_TIMEOUT; + else if (event.key == KEY_RESIZE) event.type = EVENT_RESIZE; + else { + event.type = EVENT_KEY; + if (event.key == 27) { int k = getch(); if (k == -1) event.type = EVENT_ESC; else { event.key = k; event.alt_key = 1; } } + } + r = world_event(&event, game_state); + refresh(); + timeout(TIMEOUT); + } + if (destroy_game != NULL) destroy_game(game_state); + endwin(); + return r; +} diff --git a/du8/world.h b/du8/world.h new file mode 100644 index 0000000..38962b8 --- /dev/null +++ b/du8/world.h @@ -0,0 +1,21 @@ +#ifndef _WORLD_H_ +#define _WORLD_H_ + +#include + +enum event_type { EVENT_START, EVENT_TIMEOUT, EVENT_KEY, EVENT_RESIZE, EVENT_ESC, EVENT_END }; + +struct event { + int width, height, key, alt_key, mouse_x, mouse_y, mouse_left, mouse_right, mouse_middle; + enum event_type type; + long int time_ms; +}; + +void set_cell(int character, int x, int y); +void set_color_cell(int character, int x, int y, short front_color, short back_color); +int start_world(void* (*init_game)(), int (*world_event)(struct event* event, void* game), void (*destroy_game)(void* game)); +void game_speed(int value); +void set_message(const char* message, int x, int y); +void clear_screen(); + +#endif diff --git a/du8/world.o b/du8/world.o new file mode 100644 index 0000000000000000000000000000000000000000..1e5528f2788f3c83961cc1b523f7b67443d2b8b5 GIT binary patch literal 6592 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 M6+ixOz$M!L--DX7`Tzg` literal 0 HcmV?d00001