0.8.2
Program kraluk – Královský úkol Miroslav Olšák www.olsak.net/kraluk.html
0 Obsah 1
Rozdělení zdrojových textů . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
A
Knihovna pomocných funkcí . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Modul types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Modul warning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 warning . . . 8, error . . . 8, gargc . . . 8, gargv . . . 8, mymalloc . . . 8 Modul defaults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 NAHORU . . . 9, DOLU . . . 9, VLEVO . . . 9, VPRAVO . . . 9, LENA . . . 9, PRANA . . . 9, PRADO . . . 9, LEDO . . . 9, KEY_ESC . . . 9, KEY_TAB . . . 9, KEY_ENTER . . . 9, KEY_SPACE . . . 9, KEY_UP . . . 9, KEY_LEFT . . . 9, KEY_RIGHT . . . 9, KEY_DOWN . . . 9, KEY_BACKSPACE . . . 9, KEY_DELETE . . . 9, KEY_HOME . . . 9, KEY_END . . . 9, kql_defaults . . . 9, DATADIR_LOCAL . . . 9, DATADIR . . . 9, IDIR . . . 9, IMGDIR . . . 9, MAPDIR . . . 9, BGDIR . . . 9, ANIPDIR . . . 10, INHOMEDIR . . . 10, IMGSUFFIX . . . 10, MAPSUFFIX . . . 10, SAVESUFFIX . . . 10, SAVELAST . . . 10, SAVECONF . . . 10, UPSTR . . . 10, DOWNSTR . . . 10, LEFTSTR . . . 10, RIGHTSTR . . . 10, ANIPSTR . . . 10, LANGCAT . . . 10, LANGDIR . . . 10, LANGFILE . . . 10, INPUTSUFFIX . . . 10, OUTPUTSUFFIX . . . 10, WINDOW_NAME . . . 10, ICON_NAME . . . 10, DEF_POP_SIRKA . . . 10, DEF_POP_VYSKA . . . 10, DEF_POP_X . . . 10, DEF_POP_Y . . . 10, MINRATIO . . . 10, MAXRATIO . . . 10 Modul pin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 kq_pin . . . 11, PINPOINTER . . . 11, PININT . . . 11, PINNULL . . . 11, pinpointer . . . 11, pinint . . . 11, pinnull . . . 12, spustsparem . . . 12 Modul mystring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 6.1 Nekonečný string . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 kq_string . . . 12, STRDELKA . . . 12, initstr . . . 12, zapisznak . . . 12, zestringuj . . . 13, smazstr . . . 13 6.2 Další operace se stringy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 dupnstr . . . 13, dupstr . . . 14, joinstrings . . . 14, zmensipism . . . 14, upravstring . . . 14 Modul list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 kq_list . . . 15, delkaL . . . 15, addPdoL . . . 15, addIdoL . . . 15, LdoPA . . . 16, LdoIA . . . 16, smazlist . . . 16 Modul hash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 WORD . . . 17, WORDPART . . . 17, WORDCAT . . . 17, BINDTEXT . . . 17, BINDWIN . . . 17, OUTPUT . . . 17, OTHERHASH . . . 17, hashtable . . . 17, HASHSIZE . . . 17, inithash . . . 17, hashfunc . . . 18, hash_add . . . 18, uklid . . . 18, hash_find . . . 19 Modul bindings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 keybind . . . 19, dobind . . . 19, addbind . . . 19, addgbind . . . 20, initbindings . . . 20, grestart . . . 21, popup_help . . . 21, zmensmer . . . 21, ovlpost . . . 21 Modul X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 display . . . 22, screen . . . 22, display_sirka . . . 22, display_vyska . . . 22, depth . . . 22, text_gc . . . 22, ggc . . . 22, root . . . 22, initX . . . 22, kreslianim . . . 22, mengraf . . . 22 Modul keyboard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 initklav . . . 22, xic . . . 22, xkeyznak . . . 23 Modul loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 loop . . . 24, cekalose . . . 25, udalosti . . . 25, vter . . . 25, uvter . . . 25, setdelay . . . 25, setFPSs . . . 26, FPSs . . . 26, aktuFPS . . . 26, maxFPS . . . 26, zmenFPS . . . 26 Modul timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 kq_timer . . . 27, aktutimer . . . 28, zjistitimer . . . 28, zaradtimer . . . 29, vyradtimer . . . 29, dotimers . . . 30, zmentimer . . . 30, pausetimer . . . 31, unpausetimer . . . 31,
2 3 4
5
6
7
8
9
10
11 12
13
1
0 Obsah
Program kraluk
. . . 31, deleteAtimers . . . 32, vytvortimer . . . 33, znictimer . . . 33, . . . 33, vypistimery . . . 33 Modul pixmap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . nactiXPM . . . 33, ratio . . . 33, rescalePixmap . . . 34, IMAGRAT . . . 34 14.1 kq pixmap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . kq_pixmap . . . 35, prvpix . . . 36, PIX_VYS . . . 36, PIX_SIR . . . 36, nactikqXPM . . . 36, freekqPixmap . . . 36, deletelpixmaps . . . 36, deleteApixmaps . . . 37, fix_pix . . . 37, pocet_fixpix . . . 37, fixed_pixmaps . . . 37 Modul window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . fullscreened . . . 38, OKRAJ . . . 38, win . . . 38, textwin . . . 38, real_win . . . 39, okrajwin . . . 39, real_win_vyska . . . 39, real_win_sirka . . . 39, win_x . . . 39, win_y . . . 39, win_vyska . . . 39, win_sirka . . . 39, text_sirka . . . 39, text_vyska . . . 39, pozadi . . . 39, vytvorokno . . . 39, nastavicon . . . 41, fixujokno . . . 41, okraj_to_win . . . 41, okraj_to_text . . . 41, okrajtext . . . 41, zmenokno . . . 42, velikokno . . . 42, spoctifr . . . 43, fullscreen . . . 43, unfullratio . . . 44 Modul widget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . kq_widget . . . 44, prvwidget . . . 44, poshidwid . . . 44, hidewidget . . . 44, unhidewidget . . . 45, ukazwidgety . . . 45, vytvorwidget . . . 45, zobrazwidget . . . 46, prestackujd . . . 47, prestackujn . . . 47, prohodwid . . . 47, posunzwidghet . . . 48, posunwidget . . . 48, prebarviwidget . . . 48, znicwidget . . . 49, deletelwidgets . . . 49, deleteAwidgets . . . 50, vypiswidget . . . 50, vypiswidgety . . . 50 Modul filer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . mf_otevri . . . 51, kq_filer . . . 51, mf_znak . . . 51, mf_najdi . . . 52, mf_musibyt . . . 52, mf_cislo . . . 52, mf_error . . . 53, mf_zavri . . . 53 Modul color . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . kq_color . . . 53, spustfb . . . 53, prvbarva . . . 54, pridejbarvu . . . 54 Modul map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . kq_map . . . 54, mappixel . . . 54, nactimapu . . . 54 19.1 submap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . mapa . . . 56, kq_submap . . . 56, mapa_z . . . 56, bg_map . . . 56, zmenbgmap . . . 56, vytvorsubmap . . . 57, znicsubmap . . . 57, freesm . . . 57, prvsubmap . . . 58, zaradsubmap . . . 58, vyradsubmap . . . 58, autoreloadmap . . . 58, reloadmap . . . 58, pouzijmapu . . . 59, zrussubmap . . . 59, nejvyssipix . . . 60, smpixel . . . 60, najdibarvu . . . 60, prvhidsm . . . 61, hidesubmap . . . 61, unhidesubmap . . . 61, deletelsubmaps . . . 61, deleteAsubmaps . . . 62, map_xa . . . 62, map_xb . . . 62, map_ya . . . 62, map_yb . . . 62 Modul post . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . kq_postava . . . 63, prvpost . . . 63, post_submap . . . 63, AUTOU_SOUR . . . 64, AUTOU_POST . . . 64, setchytsour . . . 64, setchytpost . . . 64, getchytsour . . . 64, zkuschytit . . . 64, autopost . . . 65, AUTOPRIOR . . . 65, spocti_z . . . 65, post_z . . . 65, hidepost . . . 65, unhidepost . . . 65, deletelposts . . . 66, menpost . . . 66, zmenapost . . . 66, updateposts . . . 66, znicpost . . . 68, deleteAposts . . . 68, posunpost . . . 68, jdipost . . . 69, kq_animpost . . . 70, ANIMPRIOR . . . 71, anip_step . . . 71, nactianip . . . 71, zmenanip . . . 73, freeanip . . . 73, deletelanips . . . 73, deleteAanips . . . 74, fix_anips . . . 74, fixed_anips . . . 74, pocet_fixanips . . . 74 Modul autopost . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . randomsmer . . . 74, auto_random . . . 75, primosmer . . . 75, vzdalenost . . . 75, post_vzdal . . . 76, uvnitrmapy . . . 76, jezed . . . 76, obejdized . . . 77, auto_clever . . . 79 Modul input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22.1 Dešifrování inputu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . provedstr . . . 80, slovo . . . 80, rozeberstr . . . 81, expandvetu . . . 82, provedvetu . . . 82, veta . . . 82, vetnyclen . . . 82, jenkat . . . 83 22.2 Syntaxe jazyka inputu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . kq_word . . . 86, STDWORD . . . 87, LANGWORD . . . 87, OBJWORD . . . 87 22.3 Interpretace načítání inputu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . add_word . . . 87, add_sent . . . 87, prvulslovo . . . 88, aktulslovo . . . 88, pocet_word . . . 88, finishws . . . 88, dfv . . . 88, nactiinput . . . 88, pps . . . 88, pfv . . . 88, startword . . . 88, deleteltimers
vypistimer
14
15
16
17
18 19
20
21
22
2
33 35
37
44
51
53 54 56
63
74
80 80
84 87
0 Obsah
Program kraluk
. . . 88, ctiradky . . . 89, ctiznak . . . 90, ulozslova . . . 90, tus . . . 92, 92, poslkat . . . 92, katnumber . . . 92, seznamslov . . . 93, wordtohash . . . 94, 95 Modul output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 kq_output . . . 98, outputstring . . . 98 23.1 Vyskakovací output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 popupoutput . . . 99, popup_info . . . 99, popupwarning . . . 99 23.2 Načítání outputu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 nactioutput . . . 101 Modul languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 prvlang . . . 103, aktulang . . . 103, jazslova . . . 105, startlang . . . 105, zmenlang . . . 105, zrusjazyk . . . 106, freeoutputs . . . 106, freeword . . . 106, freesents . . . 107, prepnilang . . . 107, zobrazjazyky . . . 108 Modul edit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 editpole . . . 108, text_pole . . . 108, delka . . . 108, loadfont . . . 109, FONTNAME . . . 109, font_info . . . 109, kursor_vyska . . . 109, HOT . . . 109, DOT . . . 109, font_y . . . 109, gelka . . . 109, gursor . . . 109, redrawtext . . . 109, cleartext . . . 109, KURSIR . . . 110, ukazkursor . . . 110, smazkursor . . . 110, pripisznak . . . 110, delete . . . 111, posunkursor . . . 111, text_enter . . . 112, prepniokraj . . . 113, posunuti . . . 113, posuntext . . . 113, LOT . . . 113, POT . . . 113, STRKAL . . . 113, STRKAP . . . 113 25.1 historie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 history . . . 114, MAXHISTORY . . . 114, poslhist . . . 114, cyklhist . . . 114, aktuhist . . . 114, ulozhist . . . 114, zkoumejhist . . . 115, zalohujtext . . . 115, ocursor . . . 115, odelka . . . 115, ogursor . . . 115, ogelka . . . 115, oposunuti . . . 115, odzaltext . . . 116, dohistory . . . 116, edithist . . . 116 25.2 Funkce pro ostatní . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 zmentext . . . 117, textcstr . . . 117, save_hist . . . 117, apply_loaded_hist . . . 118 Modul popup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 loadpopupfont . . . 119, popup_small_font . . . 119, POPUPSMALLFONT . . . 119, popup_big_font . . . 119, POPUPBIGFONT . . . 119, pfont . . . 119, vyberpfont . . . 119, POPUPBIGWIDTH . . . 119, popupstring . . . 119, zalomstring . . . 120, sirka . . . 121, vyska . . . 121, createpwin . . . 121, POPRAMOKR . . . 121, POPRAMSIR . . . 121, POPLOT . . . 121, POPPOT . . . 121, POPHOT . . . 121, POPDOT . . . 121, pwin . . . 121, pgc . . . 121, drawpopup . . . 122, popup_select . . . 122, vytvorpsel . . . 123, zruspsel . . . 123, pstr . . . 123, popvyber . . . 123, aktuselect . . . 123, posunuti . . . 124, spoctivyber . . . 124, selpocet . . . 124, sloupec . . . 124, selsirka . . . 124, selvyska . . . 124, INTERLINESKIP . . . 124, INTERCOLUMNSKIP . . . 124, SELECTOKR . . . 125, oznacsel . . . 125, odoznacsel . . . 125, drawselect . . . 125, clearselect . . . 126, posunselect . . . 126, popup_selpocet . . . 126 Modul home . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 inithome . . . 127, homedir . . . 127, homefopen . . . 127 Moduly save a load . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 28.1 Základní načítací a ukládací funkce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 soubor . . . 127, save_start . . . 127, chyba . . . 127, save_bit . . . 128, byte . . . 128, bpos . . . 128, JEDNA . . . 128, save_end . . . 128, load_start . . . 128, soubor . . . 128, chyba . . . 128, load_bit . . . 129, byte . . . 129, bpos . . . 129, load_end . . . 129, zapiscs . . . 130, cs1 . . . 130, cs1 . . . 130, cs1pos . . . 130, cs1pos . . . 130, cs2 . . . 130, cs2 . . . 130, cs2pos . . . 130, cs2pos . . . 130, check_cs . . . 130, CSL . . . 130, save_cs . . . 131, save_trit . . . 131, load_trit . . . 131, save_unsint . . . 132, load_unsint . . . 132, save_int . . . 133, load_int . . . 133, save_intoddo . . . 133, load_intoddo . . . 134, save_char . . . 134, load_char . . . 134, check_idstr . . . 134, ident_str . . . 135, save_idstr . . . 135, save_string . . . 135, load_string . . . 135, save_float . . . 136, load_float . . . 136 28.2 Ukládání vnitřních struktur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 Cislo . . . 136, save_color . . . 137, save_awid . . . 137, save_word . . . 137, save_pixmap . . . 137, save_widget . . . 137, save_submap . . . 137, save_anip . . . 138, startsent
nactikat . . . ulozvetu . . .
23
24
25
26
27 28
3
0 Obsah save_post
Program kraluk . . . 138,
save_predmet
. . . 138,
save_timer . . .
138,
save_pol
. . . 138,
save_pocty . . . 138, pocet_pix . . . 138, pocet_wid . . . 138, pocet_hwid . . . 138, pocet_sm . . . 138, pocet_hsm . . . 138, pocet_anip . . . 138, pocet_post . . . 138,
34
. . . 138, pocet_ptim . . . 138, save_kontexts . . . 139, save_winfo . . . 139, save_submaps . . . 140, save_tinfo . . . 140, save_anips . . . 141, save_posts . . . 141, save_predmets . . . 142, save_awids . . . 143 28.3 Načítání vnitřních struktur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . pocet_pix . . . 143, pocet_wid . . . 143, pocet_hwid . . . 143, pocet_sm . . . 143, pocet_hsm . . . 143, pocet_anip . . . 143, pocet_post . . . 143, pocet_tim . . . 143, pocet_ptim . . . 143, loaded_pixmaps . . . 143, loaded_widgets . . . 143, loaded_hidwids . . . 143, loaded_submaps . . . 143, loaded_bgmap . . . 143, loaded_hidmap . . . 143, loaded_anips . . . 143, loaded_posts . . . 143, loaded_timers . . . 143, loaded_pautims . . . 143, loaded_predmets . . . 143, loaded_pol . . . 143, loaded_apole . . . 143, load_pocty . . . 143, apply_load . . . 146, free_loaded . . . 148, load_kontexts . . . 149, load_word . . . 149, load_pixmaps . . . 150, load_pixmap . . . 150, load_winfo . . . 150, load_widgets . . . 150, load_widget . . . 150, load_sminfo . . . 151, load_submaps . . . 151, load_submap . . . 151, load_anips . . . 151, load_anip . . . 152, load_posts . . . 152, load_post . . . 153, load_predmets . . . 153, load_predmet . . . 154, load_tinfo . . . 154, load_timers . . . 154, load_timer . . . 154, load_pol . . . 154, load_awid . . . 155, load_awids . . . 155 28.4 Registrované funkce a proměnné . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . SL_NULL . . . 155, SL_BOOL . . . 155, SL_TRIT . . . 155, SL_CHAR . . . 155, SL_INT . . . 155, SL_FLOAT . . . 155, SL_COLOR . . . 155, SL_PIXMAP . . . 155, SL_WIDGET . . . 155, SL_SUBMAP . . . 155, SL_ANIP . . . 155, SL_POST . . . 155, SL_TIMER . . . 155, SL_POL . . . 155, SL_PREDM . . . 155, SL_WORD . . . 155, SL_AWID . . . 155, SL_FUNC . . . 156, sl_var . . . 156, add_sl_var . . . 156, save_vars . . . 156, load_vars . . . 156, save_pointer . . . 157, load_pointer . . . 157, add_sl_func . . . 157, sl_func . . . 158, save_func . . . 158, load_func . . . 159, init_sl . . . 159 28.5 Všechno dohromady . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . save_all . . . 160, load_all . . . 160, save_conf . . . 161, load_conf . . . 161 Modul gsl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . popup_sl . . . 163, gsave . . . 165, gload . . . 165, adresar . . . 165, prectidir . . . 165, fileinfo . . . 166, porovnej . . . 166, filtruj . . . 167, filtrovano . . . 167 Modul animwid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . kq_anim . . . 167, startanimwid . . . 167, animuj . . . 167 Modul pol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . kq_policko . . . 168, globbarva . . . 168, spojpol . . . 168, pol_odchfunc . . . 169, pol_prichfunc . . . 169, pridej_ps . . . 170, prvpol . . . 170, pocet_pol . . . 170, aktupol . . . 170, newpol . . . 170, set_pol . . . 171, vykreslipol . . . 171, prvnipol . . . 172, polvedle . . . 172, kql_square . . . 173, pol_submap . . . 174, pridej_psm . . . 175, pol_submapy . . . 175, pol_postava . . . 175, pridej_pp . . . 175, pol_postavy . . . 176, pol_widget . . . 176, pospw . . . 177, pw_alloc . . . 177, pw_pix . . . 177, pw_wid . . . 177, pw_xy . . . 178, rozdilz . . . 178, pridej_pw . . . 178, PW_ANIM . . . 178, pw_anim . . . 178, pol_widgety . . . 179, animpole . . . 179, vylovpix . . . 180, free_animpole . . . 181 Modul predmet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . kq_predmet . . . 181, prvpredmet . . . 181, inventar . . . 181, zaradpredmet . . . 181, vyradpredmet . . . 181, zmenprnazev . . . 182, vytvorpredmet . . . 182, predmetinv . . . 183, predmetpol . . . 183, predmetnull . . . 183, zobrazpredmet . . . 183, zobrazpredmety . . . 184, zmizpredmet . . . 184, zmizpredmety . . . 184, uzmaspredmet . . . 184, sebralspredmet . . . 184, seberpredmet . . . 184, dosahpredmet . . . 185, seberslovo . . . 185, ukazinv . . . 185, koukniinv . . . 186, UINVPOMER . . . 186, UINVSIRKA . . . 186, deleteApredmets . . . 186 Modul misc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . kql_init . . . 187, kql_start . . . 187, restart_func . . . 188, kql_restart . . . 188, kql_exit . . . 188 Modul kql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
B
Implementace příběhu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
pocet_tim
save_widgets . . . 140, save_sminfo . . . 140, save_timers . . . 140, save_pixmaps . . . 141,
29
30 31
32
33
4
143
155
160 162
167 168
181
187
189
0 Obsah 35
Program kraluk
Modul version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 Modul kraluk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . main . . . 190, restart . . . 190, panacek . . . 190 Modul kra polic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . pol . . . 190, vzamku1 . . . 191, vzamku2 . . . 191, vdrevchal . . . 191, skala1 . . . 191, skala3 . . . 191, skala2 . . . 191, skal_zebr1 . . . 191, skal_zebr2 . . . 191, peklbrana . . . 191, peklo . . . 191, schody1 . . . 191, schody2 . . . 191, lvi . . . 191, nastavpolicka . . . 191, nullujznak . . . 200, opravvodu . . . 200, opravschody . . . 203, prichpeklo . . . 203, peklohen . . . 203, vytvorcerta . . . 203, chyt_cert . . . 204, odch_hrad . . . 204, odchzebr . . . 204, prichzebr . . . 205 Modul kra input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vetyslova . . . 205, zemisto . . . 206, prozkoumej . . . 206, okoli . . . 206, znak . . . 206, dvere . . . 206, otevri . . . 207, dvere_tim . . . 207, men_dvere . . . 207, dvere_post . . . 207, zavri . . . 208, strom . . . 208, vylez . . . 208, nastrome . . . 208, slez . . . 209, snez . . . 210, tresne . . . 210, oblec . . . 210, svlec . . . 211, nalej . . . 211, voda . . . 211, vylej . . . 212, mluv . . . 212, smolicek . . . 212, jelen . . . 212, kral . . . 212, bohdanka . . . 212, maruska . . . 212, lada . . . 212, krasomila . . . 212, lotrando . . . 212, bobes . . . 212, krkavci . . . 212, jezislovo . . . 212, jezinky . . . 212, certi . . . 212, lev . . . 212, osoba . . . 212, muz . . . 212, divka . . . 212, zkusmluvit . . . 214, daruj . . . 214, spustzebr . . . 215, seber . . . 215, zapalsvicku . . . 216, domu . . . 216, ukazjaz . . . 217, konec . . . 217 Modul kra barvy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . nactigbarvy . . . 217, zem . . . 218, zed . . . 218, normal_z . . . 218, nuluj_z . . . 218, brodi1 . . . 218, brodi2 . . . 218, brodi3 . . . 218, plave . . . 218, dovody . . . 218, nebvoda1 . . . 219, nebvoda2 . . . 219, nebvoda3 . . . 219, nebvoda4 . . . 219, topise . . . 219, sucho . . . 219, breh . . . 219, paddovody . . . 219, bachakytky . . . 220, most_sm . . . 220, prich_most . . . 220, odch_most . . . 220, teletim . . . 221, teleportuj . . . 221, telepost . . . 221, padejkokos . . . 222, kokpadstep . . . 222, skalopada . . . 222, skalopad1 . . . 223, skalopad2 . . . 223, skalopad3 . . . 223, ohen . . . 223, shor . . . 223, levchyt . . . 224, barvapolic . . . 224, predTV . . . 225 Modul kra jp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . jinapost . . . 225, start_jp . . . 225, dostalkyt . . . 226, dostalsvic . . . 226, makozisek . . . 226, objev_jp . . . 226, chyt_jp . . . 226, continue_jp . . . 226, pysna_random . . . 227, null_jp . . . 227 Modul kra jezin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . prich_jezin . . . 227, auto_jezin . . . 228, jezinsmer . . . 228, jezin_chyt . . . 228, nullosobu . . . 229, prich_jelen . . . 229, jelen_step . . . 229 Modul kra jezibaba . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . startjezi . . . 229, jezibaba . . . 229, JEZI_START_X . . . 229, JEZI_START_Y . . . 229, jezitimer . . . 230, continuejezi . . . 230, jeziprichpol . . . 230, jezilastpol . . . 230, otevridvere . . . 232, jezichyt . . . 232, jezil_x . . . 232, jezil_y . . . 232, JEZI_DOLET_X . . . 232, JEZI_DOLET_Y . . . 232, jezinull . . . 233, jezicekej . . . 233, jezichytej . . . 234, houpejzebr . . . 234, houp_step . . . 234, jezishor . . . 234, jezivzdej . . . 234 Modul kra krk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . krkstav . . . 235, prich_krk . . . 235, krksedi . . . 235, krkleti . . . 235, vytvor_krk . . . 235, plasptaky . . . 236, promenujkrk . . . 236, odkrk . . . 236, krk_chyt . . . 236, null_krk . . . 236, prich_bohd . . . 237, odch_bohd . . . 237, zdrchal . . . 237 Modul kra provaz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . lvistav . . . 237, provazstep . . . 237, wprovaz . . . 239, prycodzdi . . . 239, privaz . . . 240, kamen . . . 241, posun . . . 241 Modul kra predm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vytvorpredmety . . . 242, kybl . . . 242, pernicek . . . 242, brneni . . . 242, kokos . . . 242, mkozisek . . . 242, hvezdicka . . . 242, odsmolicka . . . 242, kaminek . . . 242,
189
VERSION . . .
36 37
38
39
40
41
42
43
44
45
5
190 190
205
217
225
227
229
235
237
242
1 Rozdělení zdrojových textů
Program kraluk
. . . 242, slanka . . . 242, kytka . . . 242, svicka . . . 242, sluchatko . . . 242, . . . 242, zebrik . . . 242 Modul kra animpost . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 nactianipy . . . 243, chozeni . . . 243, brnanip . . . 243, vevode1 . . . 243, vevode2 . . . 243, vevode3 . . . 243, plavani . . . 243, topeni . . . 243, padani . . . 243, lezeni . . . 243, privazan . . . 243, teleanip . . . 243, teleanip2 . . . 243, jezianip . . . 243, jezileti . . . 243 Modul kra prom . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 initprom . . . 243 Modul kra save . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 registrujpf . . . 244 truhlicka
princezna
46
47 48
C 49 50 51
Rejstříky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Restřík modulů . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Rejstřík funkcí, struktur a proměnných . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Literatura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
245 245 246 256
1 Rozdělení zdrojových textů Zdrojové texty jsou rozděleny do modulů. Každý modul řeší pokud možno jednu uzavřenou myšlenku z pohledu programátora. Zdrojové texty každého modulu jsou ve dvou souborech: *.h a *.c. Například zdrojáky modulu hash jsou v souborech hash.h a hash.c. Moduly se kompilují zvlášť do výsledného *.o (např. hash.o). V závěru se slinkují všechny moduly *.o do výsledného programu. Soubory *.c obsahují „soukroméÿ zdrojové texty modulu, zatímco *.h obsahují deklarace paměťových struktur, globálních proměnných a prototypů funkcí, které jsou nejvíce spojeny s daným modulem, ale jsou sdíleny i některými dalšími moduly. Dokumentace ke zdrojákům je členěna do kapitol přesně podle jednotlivých modulů, tj. každá kapitola popisuje jeden modul. Dokumentace je zapsána v souborech *.d (například hash.d). Tyto soubory jsou (společně s *.h a *.c) čteny TEXem a je z nich vytvořen PDF soubor, který právě čtete. Moduly programu jsou rozděleny do dvou skupin: A. knihovna pomocných funkcí a B. implementace příběhu. Pokud chce někdo vdechnout hře jiný příběh, použije funkce a datové struktury z první skupiny a inspiruje se, jak jsou tyto funkce zde použity ve skupině druhé. Moduly jsou zde seřazeny od základních či pomocných funkcí k funkcím složitějším, které používají předchozí funkce. Dokumentace se ale dá číst i od konce, protože jednotlivé výskyty funkcí, proměnných a struktur jsou prolinkovány (v PDF souboru je to klikací). A. knihovna pomocných funkcí 2. types . . . . . . . . . . . . typedef některých struktur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 3. warning . . . . . . . . . . funkce pro varující a chybové hlášky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 4. defaults . . . . . . . . . výchozí hodnoty programu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 5. pin . . . . . . . . . . . . . . deklarace typu kq_pin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 6. mystring . . . . . . . . . stringy neomezené délky a operace se stringy . . . . . . . . . . . . . . . . . . . . . . . 12 7. list . . . . . . . . . . . . . jednoduchý zásobník . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 8. hash . . . . . . . . . . . . . vyhledávání ve slovníku . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 9. bindings . . . . . . . . . klávesové zkratky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 10. X . . . . . . . . . . . . . . . . nízkoúrovňové funkce spolupracující s X . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 11. keyboard . . . . . . . . . vstup z klávesnice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 12. loop . . . . . . . . . . . . . hlavní smyčka programu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 13. timer . . . . . . . . . . . . časovač programu (Xlib neimplementuje svůj časovač) . . . . . . . . . . . . . . . 27 14. pixmap . . . . . . . . . . . čtení obrázků z XPM souborů, škálování . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 15. window . . . . . . . . . . . členění okna programu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 16. widget . . . . . . . . . . . datová struktura elementu obrázku . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 17. filer . . . . . . . . . . . . čtení mapy z XPM souboru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 18. color . . . . . . . . . . . . co dělá která barva mapy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 19. map . . . . . . . . . . . . . . pole barev pro různé aktivity ve scéně . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 20. post . . . . . . . . . . . . . struktura kq_postava (widget+submap+timer) . . . . . . . . . . . . . . . . . . . . . 63 21. autopost . . . . . . . . . algoritmy pro automatické ovládání postavy . . . . . . . . . . . . . . . . . . . . . . . . 74 22. input . . . . . . . . . . . . interpretace vstupních příkazů . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 23. output . . . . . . . . . . . konverze z labeblíku na nápis pro výstup . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 6
2 Modul types 24. 25. 26. 27. 28. 28. 29. 30. 31. 32. 33. 34.
Program kraluk
languages . . . . . . . . přepínání jazyků . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . edit . . . . . . . . . . . . . spodní editační řádek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . popup . . . . . . . . . . . . okno s výstupním textem nebo výběrem . . . . . . . . . . . . . . . . . . . . . . . . . . . home . . . . . . . . . . . . . práce se soubory v domovském adresáři . . . . . . . . . . . . . . . . . . . . . . . . . . . save . . . . . . . . . . . . . uložení stavu programu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . load . . . . . . . . . . . . . restaurování stavu programu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . gsl . . . . . . . . . . . . . . grafický save a load . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . animwid . . . . . . . . . . automaticky animovaný obrázek na políčku . . . . . . . . . . . . . . . . . . . . . . . . pol . . . . . . . . . . . . . . políčko neboli jedna scéna hry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . predmet . . . . . . . . . . předměty, inventář . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . misc . . . . . . . . . . . . . init, start, restart, exit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . kql . . . . . . . . . . . . . . načtení všech hlavičkových souborů . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
103 108 119 127 127 127 162 167 168 181 187 189
B. implementace příběhu 35. version . . . . . . . . . . definice aktuální verze . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36. kraluk . . . . . . . . . . . funkce main() a restart() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37. kra_polic . . . . . . . . inicializace políček (scén hry), funkce přechodů . . . . . . . . . . . . . . . . . . . . . 38. kra_input . . . . . . . . funkce reagující na příkazy uživatele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39. kra_barvy . . . . . . . . funkce reagující na barevnou mapu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40. kra_jp . . . . . . . . . . . všelijaké postavy hry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41. kra_jezin . . . . . . . . smolíček, jelen, jezinky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42. kra_jezibaba . . . . . aktivity ježibaby . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43. kra_krk . . . . . . . . . . krkavci, Bohdanka . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44. kra_provaz . . . . . . . animace spouštění a vytahování po provazu . . . . . . . . . . . . . . . . . . . . . . . . 45. kra_predm . . . . . . . . načtení předmětů . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46. kra_animpost . . . . . animace postavy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47. kra_prom . . . . . . . . . inicializace proměnných . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48. kra_save . . . . . . . . . registrace funkcí a proměnných pro ukládání pozic . . . . . . . . . . . . . . . . . .
189 190 190 205 217 225 227 229 235 237 242 243 243 244
A
Knihovna pomocných funkcí
2 Modul types Tento modul obsahuje pouze háčkový soubor, který pomocí typedef umožní u některých struktur nepoužívat před názvem struct. types.h 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
typedef typedef typedef typedef typedef typedef typedef typedef typedef typedef typedef typedef typedef typedef typedef typedef typedef typedef typedef
struct struct struct struct struct struct struct struct struct struct struct struct struct struct struct struct struct struct struct
kq_pin kq_list kq_string kq_word kq_filer kq_timer kq_color kq_map kq_submap kq_pixmap kq_widget kq_anim kq_animpost kq_postava kq_policko kq_predmet kq_output sl_func sl_var
kq_pin; kq_list; kq_string; kq_word; kq_filer; kq_timer; kq_color; kq_map; kq_submap; kq_pixmap; kq_widget; kq_anim; kq_animpost; kq_postava; kq_policko; kq_predmet; kq_output; sl_func; sl_var;
7
3 Modul warning
Program kraluk
20: 21: typedef struct pol_widget pol_widget; 22: typedef struct pol_submap pol_submap; 23: typedef struct pol_postava pol_postava;
3 Modul warning Tento modul vypisuje chybové hlášky. Funkce warning vypíše varování. Má však počet parametrů stejným způsobem roztahovací jako printf. Narozdíl od funkce printf ovšem není třeba na konec psát \n, jde to do standardního erroru a navíc něco připíše na začátek. warning.c 6: void warning (char *s, ...) 7: { 8: va_list vl; 9: 10: fprintf(stderr, "%s warning: ", gargv[0]); 11: va_start(vl, s); 12: vfprintf(stderr, s, vl); 13: va_end(vl); 14: fprintf(stderr, "\n"); 15: }
Funkce error funguje skoro stejně jako warning, až na dvě drobné odlišnosti: • Funkce warning napíše warning, Funkce error napíše error. • Funkce error narozdíl od funkce warning ukončí program. warning.c 17: void error (char *s, ...) 18: { 19: va_list vl; 20: 21: fprintf(stderr, "%s error: ", gargv[0]); 22: va_start(vl, s); 23: vfprintf(stderr, s, vl); 24: va_end(vl); 25: fprintf(stderr, "\n"); 26: 27: exit(-1); 28: }
Při výpisu chybových hlášek tyto funkce vypíší i název programu. Kvůli tomu v tomto modulu mám ještě proměnné gargc a gargv, což jsou kopie parametrů funkce main. Do těchto proměnných je uloži funkce kql_init. warning.h 1: int gargc; 2: char **gargv;
Funkce mymalloc naalokuje paměť (voláním knihovní funkce malloc) a v případě neúspěchu zkolabuje pomocí funkce error. warning.c 30: void *mymalloc (unsigned int size) 31: { 32: void *vysledek; 33: 34: if(!(vysledek = malloc(size))) error("Allocation of size %d failed", size); 35: return vysledek; 36: }
void warning(): 8, 19, 23, 26–28, 30–31, 36–37, 52, 55, 57–58, 61, 64, 68, 72–74, 81, 83, 87, 89–94, 96–97, 99, 101–104, 107–108, 117–120, 122–123, 127–131, 133–135, 137, 141, 144–146, 152, 154, 156–162, 166, 168, 179–180, 182–185, 187, 211–213, 217, 220–221 void error(): 8, 14, 22, 34, 51, 53, 109, 119 int gargc: 8, 40, 187 char gargv: 8, 40–41, 187 void *mymalloc(): 8, 13–16, 18–19, 33, 35–36, 45, 51, 54, 56–57, 59, 67, 72, 82–83, 88, 91, 94, 96–97, 100, 102–105, 108, 115, 156, 158, 163, 166, 169–171, 175–177, 179–180, 182, 185
8
4 Modul defaults
Program kraluk
4 Modul defaults Implictiní hodnoty proměnných jsou nastaveny v tomto modulu. Pomocí #define jsou nastaveny konstanty, které určují směr. defaults.h 80: 81: 82: 83: 84: 85: 86: 87:
#define #define #define #define #define #define #define #define
NAHORU DOLU VLEVO VPRAVO LENA PRANA PRADO LEDO
0 1 2 3 4 5 6 7
// // // //
vlevo nahoru vpravo nahoru vpravo dolu vlevo dolu
Dále jsem v modulu gsl použil kódy (keycodes) některých kláves: defaults.h 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102:
#define #define #define #define #define #define #define #define #define #define #define #define
KEY_ESC KEY_TAB KEY_ENTER KEY_SPACE KEY_UP KEY_LEFT KEY_RIGHT KEY_DOWN KEY_BACKSPACE KEY_DELETE KEY_HOME KEY_END
9 23 36 65 98 100 102 104 22 107 97 103
Některé proměnné s konstantní hodnotou (deklarované v defaults.h) jsou inicializovány ve funkci kql_defaults při startu programu. Sice by mohly být vymezeny pomocí #define, ale pak by je nešlo změnit například po přečtení parametrů příkazové řádky. Původní záměr totiž byl, že tyto hodnoty bude možné v parametrech příkazové řádky měnit, i když to zatím není naprogramováno. Ve funkci kql_defaults jsou nejprve nastaveny hodnoty pro názvy adresářů a částí názvů souborů. Proměnná DATADIR_LOCAL obsahuje název adresáře, kde hledá program data jako první a DATADIR je název adresáře, kde hledá program data, pokud je nenašel v DATADIR_LOCAL. Měl by to být nějaký systémový adresář. Pokud správce systému před kompilací v Makefile nastaví IDIR, je použita tato hodnota, jinak se použije implicitní hodnota. defaults.c 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
void kql_defaults() { // Soubory a adresare: DATADIR_LOCAL = "./kraluk-data"; // tam hledam jako prvni #ifdef IDIR DATADIR = IDIR; // systemovy adresar z Makefile #else DATADIR = "/usr/local/share/kraluk-data"; // kdyz v DATADIR_LOCAL nic neni #endif IMGDIR = "/images/"; // obrazky jsou v DATADIR+IMGDIR MAPDIR = "/images/maps/"; // barevne mapy jsou v DATADIR+MAPDIR BGDIR = "backgrounds/"; // zakladni obrazky scen v DATADIR+IMGDIR+BGDIR
NAHORU: 20–21, 69–72, 169, 172, 199–202, 204, 207–208, 219–221, 224, 228–229, 231–232, 240–241 DOLU: 20–21, 69–72, 169, 172, 190, 199–204, 209, 216, 220–221, 228–229, 231–232, 235, 240–241 VLEVO: 20–21, 69–72, 169, 172, 199–200, 220, 228, 230, 232, 240–241 VPRAVO: 20–21, 69–72, 168–169, 172, 199–200, 220, 225, 228, 232, 238, 240–241 LENA: 20–21 PRANA: 20–21 PRADO: 20–21 LEDO: 20–21 KEY_ESC: 119–120, 123, 163 KEY_TAB: 164 KEY_ENTER: 119–120, 123, 164 KEY_SPACE: 119–120 KEY_UP: 123, 164 KEY_LEFT: 123, 164 KEY_RIGHT: 123, 164 KEY_DOWN: 123, 164 KEY_BACKSPACE: 164 KEY_DELETE: 164 KEY_HOME: 164 KEY_END: 164 void kql_defaults(): 9–11, 187, 190 char *DATADIR_LOCAL: 9, 187 char *DATADIR: 9–10, 33–34, 54, 89, 101, 104, 187 IDIR: 9 char *IMGDIR: 9–10, 33–34 char *MAPDIR: 9, 54 char *BGDIR: 9, 39, 42
9
4 Modul defaults
Program kraluk
21: ANIPDIR = "animposts/"; // animace postav v DATADIR+IMGDIR+ANIPDIR 22: INHOMEDIR = ".kraluk"; // ukladani a cteni pozic v $HOME/INHOMEDIR 23: 24: IMGSUFFIX = ".xpm"; // pripona pro obrazky 25: MAPSUFFIX = ".xpm"; // pripona pro mapy 26: SAVESUFFIX = ".kqs"; // pripona pro soubory pozic 27: SAVELAST = "lastpos"; // posledni pozice (ulozena pri ukonceni programu) 28: SAVECONF = "lastconf"; // konfigurace (ulozena pri ukonceni programu) 29: 30: UPSTR = "/up"; // animace postavy (nahoru) DATADIR+IMGDIR+nazev+UPSTR+n+IMGSUFFIX 31: DOWNSTR = "/down"; // animace postavy (dolu) 32: LEFTSTR = "/left"; // animace postavy (doleva) 33: RIGHTSTR = "/right"; // animace postavy (doprava) 34: ANIPSTR = "/anim"; // animace postavy (bez smeru) 35: 36: // Jazyky: 37: 38: LANGCAT = "languages"; // kategorie slov jazyku 39: LANGDIR = "/languages/"; // adresar se soubory jazyku DATADIR+LANGDIR 40: LANGFILE = "_languages.txt"; // soubor se seznamem jazyku DATADIR+LANGDIR+LANGFILE 41: 42: INPUTSUFFIX = "_input.txt"; // soubor inputu DATADIR+LANGDIR+zkratka+INPUTSUFFIX 43: OUTPUTSUFFIX = "_output.txt"; // soubor textu DATADIR+LANGDIR+zkratka+OUTPUTSUFFIX 44: 45: // Udaje o oknu: 46: 47: WINDOW_NAME = "Kralovsky ukol"; // nazev okna programu 48: ICON_NAME = "kraluk"; // nazev ikony programu
Dále jsou ve funkci kql_defaults inicializovany parametry pro vzhled editačního řádku a vyskakovacího okna. Proměnné DEF_POP_SIRKA, DEF_POP_VYSKA, DEF_POP_X a DEF_POP_Y jsou rozměry, které jsou obvykle předávány funkcím pro vyskakovací okno. Proměnné MINRATIO a MAXRATIO udávají hranice, ve kterých se může pohybovat poměr zvětšení. defaults.c 50: // Editace textu: 51: 52: FONTNAME = "-*-helvetica-bold-r-normal-*-25-*-*-*-*-*-iso8859-2"; 53: HOT = 4; // horni okraj textu 54: DOT = HOT; // dolni okraj textu 55: LOT = HOT; // levy okraj textu 56: POT = LOT; // pravy okraj textu 57: STRKAL = 30; // strkani kursoru doleva 58: STRKAP = STRKAL; // strkani kursoru doprava 59: KURSIR = 4; // sirka kursoru 60: 61: // Vyskakovaci okno: 62: 63: POPUPSMALLFONT = "-*-helvetica-bold-r-normal--20-*-*-*-*-*-iso8859-2"; 64: POPUPBIGFONT = "-*-helvetica-bold-r-normal--34-*-*-*-*-*-iso8859-2"; 65: POPUPBIGWIDTH = 800; 66: POPRAMOKR = 5; 67: POPRAMSIR = 2; 68: POPHOT = 5; 69: POPDOT = POPHOT;
char *ANIPDIR: 10, 72 char *INHOMEDIR: 10, 127 char *IMGSUFFIX: 10, 33–34 char *MAPSUFFIX: 54 char *SAVESUFFIX: 165–166 char *SAVELAST: 188 char *SAVECONF: 161 char *UPSTR: 10, 72 char *DOWNSTR: 72 char *LEFTSTR: 72 char *RIGHTSTR: 72 char *ANIPSTR: 72 char *LANGCAT: 105 char *LANGDIR: 10, 89, 101, 104 char *LANGFILE: 10, 104 char *INPUTSUFFIX: 10, 89 char *OUTPUTSUFFIX: 10, 101 char *WINDOW_NAME: 40 char *ICON_NAME: 40–41 int DEF_POP_SIRKA: 11, 21, 99–100, 107–108, 163, 184–186 int DEF_POP_VYSKA: 11, 21, 99–100, 107–108, 163, 184–186 int DEF_POP_X: 11, 21, 99–100, 107–108, 163, 184–186 int DEF_POP_Y: 11, 21, 99–100, 107–108, 163, 184–186 int MINRATIO: 11, 43 int MAXRATIO: 11, 43
10
5 Modul pin
Program kraluk
70: POPLOT = POPHOT; 71: POPPOT = POPLOT; 72: INTERLINESKIP = 2; 73: INTERCOLUMNSKIP = 20; 74: SELECTOKR = 1; 75: 76: DEF_POP_SIRKA = 0.8; 77: DEF_POP_VYSKA = 0.7; 78: DEF_POP_X = 0.5; 79: DEF_POP_Y = 0.5; 80: 81: UINVPOMER = 0.5; 82: UINVSIRKA = 0.5; 83: 84: // Predefinovatelny zbytek: 85: 86: OKRAJ = 3; 87: MINRATIO = 1; 88: MAXRATIO = 20; 89: ANIMPRIOR = -50; 90: AUTOPRIOR = 50; 91: IMAGRAT = 1;
Konečně jsou ve funkci kql_defaults inicializovány hodnoty následujících globálních proměnných: defaults.c 95: 96: 97: 98: 99: }
fullscreened = 0; // unfullratio = 0; okrajtext = 0; ratio = 2;
5 Modul pin Tento modul deklaruje obecný datový typ kq_pin, který může být pointer, int nebo nic. Pin je zkratka těchto tří možností. pin.h 9: struct kq_pin{ 10: int typ; 11: union{ 12: void *p; 13: int i; 14: } u; 15: };
Položka typ v této struktuře určuje, co bude daný pin zastupovat. Může nabývat jednu z následujících hodnot, jejichž význam je zřejmý: pin.h 3: #define PINPOINTER 2 4: #define PININT 1 5: #define PINNULL 0
Dále se ve struktuře nachází union, ve kterém je v položce i uložen případný int a v položce p případný pointer. Pokud typ == PINNULL, je jedno v jakém stavu se tento union nachází. Pro snadné vytváření pinů je k dispozici funkce pinpointer, která dostane pointer a vrátí pin, jenž ho zastupuje, dále funkce pinint, která dostane int a vrátí pin, který ho zastupuje. pin.c 6: kq_pin pinpointer (void *p) 7: { 8: kq_pin vysledek; 9: vysledek.typ = PINPOINTER; 10: vysledek.u.p = p; kq_pin: 6–7, 11–12, 17–20, 27, 33, 81, 86, 93–94, 99, 101, 105, 158–159, 246 PINPOINTER: 11, 19, 81, 99, 102, 159, 185 PININT: 12, 93, 158–159 PINNULL: 11–12, 158–159, 187 kq_pin pinpointer(): 11–12, 20, 65, 68, 73, 94, 102, 104, 167, 182, 224, 226, 233–234, 236, 239 kq_pin pinint(): 12, 20–21, 93, 105, 207–208
11
6 Modul mystring 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
Program kraluk
return vysledek; } kq_pin pinint (int i) { kq_pin vysledek; vysledek.typ = PININT; vysledek.u.i = i; return vysledek; }
Pro pin, jenž nezastupuje nic, není třeba deklarovat funkci, jelikož takový pin je jen jeden. Vedle funkcí je tedy ještě deklarovaná proměnná pinnull, jejíž typ je nastaven ve funkci kql_init(). pin.h 19: kq_pin pinpointer(void *p); 20: kq_pin pinint(int i); 21: kq_pin pinnull;
Datový typ kq_pin se často používá jakožto parametr pro uloženou funkci, které se předá takový parametr, který ten pin zastupuje. To provede funkce spustsparem. pin.c 24: void spustsparem (void (*funkce)(), kq_pin *parametr) 25: { 26: if(parametr->typ == PINNULL) funkce(); 27: else if(parametr->typ == PININT) funkce(parametr->u.i); 28: else funkce(parametr->u.p); 29: }
6 Modul mystring Tento modul má dvě části. V první je řešen nekonečný string a v druhé další operace se stringy. 6.1
Nekonečný string Nekonečný string zastupuje datový typ kq_string. mystring.h
7: 8: 9: 10: 11: 12: 13: 14: 15:
struct caststr{ char ch[STRDELKA]; struct caststr *next; }; struct kq_string{ int delka; struct caststr *posledni; };
Položka delka udává počet znaků toho stringu a posledni jsou zásobníkovým způsobem řazeny pole znaků o velikosti STRDELKA. mystring.h 3: #define STRDELKA 20
Tato pole nejsou ukončena nulou jako v běžných strinzích, takže které znaky do stringu patří a které ne je třeba spočítat z položky delka. Než se s nekonečným stringem začne pracovat, je třeba ho inicializovat funkcí initstr. mystring.c 11: void initstr (kq_string *str) 12: { 13: str->posledni = NULL; 14: str->delka = 0; 15: }
Poté se s ním dají dělat dvě věci. Můžete k nekonečnému stringu str přidat na konec jeden znak ch funkcí zapisznak. kq_pin pinnull: 12, 20–21, 87–88, 94, 187, 221–222, 226, 229–232, 235 void spustsparem(): 12, 19, 30 kq_string: 7, 12–13, 15, 90, 101, 104 STRDELKA: 12–13 void initstr(): 12–13, 90, 102, 104 void zapisznak(): 13, 90, 102–104
12
6 Modul mystring
Program kraluk mystring.c
32: void zapisznak (char ch, kq_string *str) 33: { 34: struct caststr *pom; 35: 36: if(str->delka%STRDELKA == 0){ 37: pom = (struct caststr *)mymalloc(sizeof(struct caststr)); 38: pom->next = str->posledni; 39: str->posledni = pom; 40: } 41: str->posledni->ch[str->delka%STRDELKA] = ch; 42: 43: str->delka++; 44: }
A ta druhá možnost je převod na standardní C-čkový string, který vrátí funkce zestringuj. mystring.c 48: char *zestringuj (kq_string *str) 49: { 50: int i, j; 51: struct caststr *pom; 52: char *vysledek; 53: 54: vysledek = (char *)mymalloc((str->delka+1)*sizeof(char)); 55: 56: i = str->delka-1; 57: i /= STRDELKA; 58: i *= STRDELKA; 59: j = str->delka - i; 60: 61: for(pom = str->posledni; pom; pom = pom->next){ 62: strncpy(&vysledek[i], pom->ch, j); 63: j = STRDELKA; 64: i -= STRDELKA; 65: } 66: vysledek[str->delka] = 0; 67: 68: return vysledek; 69: }
Funkce zestringuj namallocuje nový string, takže když už ho nebudete potřebovat, je vhodné ho uvolnit funkcí free. Navíc původní nekonečný string neuvolní (jeho části), ale ponechá ho v původním stavu. Uvolnit se dá funkcí smazstr, která ho zároveň pronuluje a připraví k dalšímu použití. mystring.c 19: void smazstr (kq_string *str) 20: { 21: struct caststr *pom, *pomo; 22: 23: for(pom = str->posledni; pom; pom = pomo){ 24: pomo = pom->next; 25: free(pom); 26: } 27: initstr(str); 28: }
6.2
Další operace se stringy
V manuálové stránce o string jsem našel funkci strndup, která vytvoří nový string z určitého počtu znaků původního stringu. Kompilátor se však tvářil, že tuto funkci nezná, tak jsem se po chvíli bádání rozhodl, že si naprogramuji svojí takovou funkci, kterou jsem pojmenoval dupnstr. Navíc v této funkci použiji svůj mymalloc. mystring.c 73: char *dupnstr (char *src, int n) 74: { 75: char *vysledek; char *zestringuj(): 13, 90, 102, 104 117
void smazstr(): 13, 90, 102, 104
13
void dupnstr(): 13, 92–94,
6 Modul mystring 76: 77: 78: 79: 80: 81: 82: }
Program kraluk
vysledek = mymalloc((n+1)*sizeof(char)); strncpy(vysledek, src, n); vysledek[n] = 0; return vysledek;
Funkci strdup, která zduplikuje string, kompilátor zná, ale přesto zde mám funkci dupstr, která v případě selhání zavolá funkci error, takže program stejně spadne, ale alespoň je jasné proč. mystring.c 86: char *dupstr (char *src) 87: { 88: char *vysledek; 89: 90: if(!(vysledek = strdup(src))) error("string duplication failed: \"%s\"", src); 91: return vysledek; 92: }
Dále je zde funkce joinstrings, která vymallokuje nový string jakožto spojení jejich parametrů. Poslední parametr této funkce musí být NULL, aby jí bylo jasné, kde seznam parametrů končí. mystring.c 96: char *joinstrings(char *prvni, ...) 97: { 98: va_list vl; 99: char *pomstr, *vysledek; 100: int i=1; 101: 102: va_start(vl, prvni); 103: for(pomstr=prvni; pomstr; pomstr = va_arg(vl, char *)){ 104: i += strlen(pomstr); 105: } 106: va_end(vl); 107: 108: vysledek = (char *)mymalloc(i*sizeof(char)); 109: 110: i=0; 111: va_start(vl, prvni); 112: for(pomstr=prvni; pomstr; pomstr = va_arg(vl, char *)){ 113: strcpy(&vysledek[i], pomstr); 114: i += strlen(pomstr); 115: } 116: if(!prvni) vysledek[0] = 0; 117: 118: return vysledek; 119: }
Funkce zmensipism dostane znak a vrátí znak. Pokud dostane malé písmeno, vrátí ten samý znak. Dostane-li velké písmeno, vrátí to samé písmenko, ale malé. Pokud však dostane něco jiného vrátí mezeru. mystring.c 123: char zmensipism (char ch) 124: { 125: if(isalpha(ch)) return tolower(ch); 126: else return ’ ’; 127: }
Tuto funkci využívá funkce upravstring, která na všechny znaky stringu aplikuje zmensipism a pak odebere mezery z okrajů a více mezer u sebe nahradí jednou mezerou. mystring.c 131: void upravstring (char *str) 132: { 133: int k,l,m; 134: 135: for(m=l=k=0; str[k]; k++){ char *dupstr(): 14, 18, 36, 57, 81, 91, 93, 107, 119, 175–177, 182 34, 39, 42, 54, 72, 89, 101, 104, 107, 127, 130, 165–166, 188, 206 void upravstring(): 14, 81, 86, 91–92, 103–104
14
char *joinstrings(): 14, char zmensipism(): 14–15
7 Modul list
Program kraluk
136: str[l] = zmensipism(str[k]); 137: if(m==0){ 138: if(str[l] != ’ ’){ 139: m=1; 140: l++; 141: } 142: } 143: else{ 144: if(str[l] == ’ ’) m=0; 145: l++; 146: } 147: } 148: if(l > 0 && str[l-1] == ’ ’) str[l-1] = 0; 149: else str[l] = 0; 150: }
7 Modul list Tento modul řeší jednoduchý zásobník, jenž je zastoupen ukazatelem na datový typ kq_list. list.h 3: struct kq_list{ 4: union{ 5: void *p; 6: int i; 7: } u; 8: kq_list *next; 9: };
Fungují nad ním zhruba stejné operace jako nad kq_string, ale nejde o zásobník charů, ale intů nebo pointerů. Inicializaci není třeba provádět funkcí, stačí do daného kq_list dosadit NULL. Není v něm však nikde přímo napsána jeho délka. Je třeba ji spočítat funkcí delkaL. list.c 44: int delkaL (kq_list *l) 45: { 46: int vysledek; 47: 48: for(vysledek = 0; l; l = l->next) vysledek++; 49: 50: return vysledek; 51: }
To, zda jde o integery nebo pointery není nikde přesně řečeno a je tedy třeba vědět s jakým zásobníkem se pracuje. Pro přidání pointeru do zásobníku je zde funkce addPdoL, funkce addIdoL přidá int. list.c 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39:
void addPdoL (void *p, kq_list **l) { kq_list *pom; pom = (kq_list *)mymalloc(sizeof(kq_list)); pom->u.p = p; pom->next = *l; *l = pom; } void addIdoL (int i, kq_list **l) { kq_list *pom; pom = (kq_list *)mymalloc(sizeof(kq_list)); pom->u.i = i; pom->next = *l; *l = pom; kq_list: 7, 15–16, 80–82, 88, 91–93, 95, 101, 168, 170–173 int delkaL(): 15–16, 95–96 void addPdoL(): 15, 81, 88, 93–94, 103 void addIdoL(): 15, 92
15
8 Modul hash
Program kraluk
40: }
List se dá převést na pole pointerů nebo intů, jehož poslední člen je NULL nebo nula pomocí funkcí LdoPA (pole pointerů) a LdoIA (pole intů). list.c 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81:
void **LdoPA (kq_list *l) { int i; void **vysledek; i = delkaL(l); vysledek = (void **)mymalloc((i+1)*sizeof(void *)); vysledek[i] = NULL; for(;l; l = l->next) vysledek[--i] = l->u.p; return vysledek; } int *LdoIA (kq_list *l) { int i; int *vysledek; i = delkaL(l); vysledek = (int *)mymalloc((i+1)*sizeof(int)); vysledek[i] = 0; for(;l; l = l->next) vysledek[--i] = l->u.i; return vysledek; }
Nakonec se dá list uvolnit z paměti funkcí smazlist. Tato funkce navíc do toho listu dosadí NULL, čímž ho připraví pro další použití. list.c 8: void smazlist (kq_list **l) 9: { 10: kq_list *pom; 11: 12: while(*l){ 13: pom = (*l)->next; 14: free(*l); 15: *l = pom; 16: } 17: *l = NULL; 18: }
8 Modul hash Program potřebuje ukládat a vyhledávat slovníkové údaje. Například při analýze věty, kterou vkládá uživatel, je potřeba větu rozebrat na slova a podívat se do slovníku, zda taková slova známe a co znamenají. Nebo keybinding. Pro tyto účely se v programech běžně implementuje tzv. hash. Jedná se o implemantaci slovníku, který obsahuje množinu uspořádaných dvojic [klíč (slovo), hodnota (jak reagovat)]. Bude potřeba řešit dotazy, kdy známe klíč, a hledáme hodnotu. Hash je inteligentní implementace slovníku, kdy program nevyhledává mezi jednotlivými klíči sekvenčně, ale poněkud rychleji. Viz Knuth: The Art of Computer Programming, díl 3, strany 513–557. V programu jsem použil variantu algoritmu popsaného v uvedené knize na straně 520. Klíč ve slovníku nebude v mém programu slovo samotné, ale ještě k němu přidám typ slova. Slova stejně znějící různého typu totiž vyžadují úplně jinou reakci. Následuje výčet typů slov. void **LdoPA(): 16, 80, 88, 94–95 102, 107
int *LdoIA(): 16, 92
16
void smazlist(): 16, 80–81, 88, 92, 94–95,
8 Modul hash
Program kraluk hash.h
3: 4: 5: 6: 7: 8: 9: 10:
#define #define #define #define #define #define
WORD WORDPART WORDCAT BINDTEXT BINDWIN OUTPUT
1 2 3 4 5 6
#define OTHERHASH 0
// // // // // //
slovo cast slova kategorie slova klavesova zkratka, v modu psani, vice v bindings.h klavesova zkratka, v modu chozeni, vice v bindings.h odkaz na text pro output
// cokoli dalsiho, nevsima si toho funkce uklid()
Hodnota ve slovníku (jak reagovat) je implementovaná datovým typem kq_pin. Slovník je implementován jako pole hashtable délky HASHSIZE hash.h 14: #define HASHSIZE 797
// velikost hashoveho pole
Délka pole se podle doporučení volí jako prvočíslo zhruba tak velké, jak velký očekáváme slovník. Hodnoty pole jsou pointery do struktury hash: hash.h 18: struct hash{ 19: char typ; // informace, na zaklade ktere se hleda 20: char *string; // informace, na zaklade ktere se hleda 21: kq_pin informace; // informace, ktera se hleda 22: struct hash *next; // dalsi policko hashe (je pouzito separate chaining) 23: } *hashtable[HASHSIZE];
Každý klíč dostane přiděleno pomocí hashovací funkce číslo v rozsahu 0..HASHSIZE-1, které je indexem v poli hashtable. Pokud se sejdou dva nebo více různých klíčů se stejnou hodnotou hashovací funkce, je nutno řetězit jednotlivé struktury hash, jak ukazuje obrázek. Pole hashtable o velikosti HASHSIZE je na obrázku zakresleno svisle vlevo. Např. klíč1 má na obrázku hashovací index 3 stejně jako klíč5. Má-li se vyhledat hodnata ke klíč5, program vyhodnotí index 3 a dále projde „řádekÿ na obrázku sekvenčně.
hashtable
0
NULL
klic2 hod2
1 2
NULL
NULL
3 4
klic5 hod5 NULL
klic1 hod1
klic7 hod7
NULL
HASHSIZE
Funkce inithash vynuluje hashtable a použije se na začátku programu. hash.c 22: void inithash () 23: { 24: int i;
// Vynuluje hashove pole.
WORD: 19, 81, 94, 103, 106 WORDPART: 81, 94, 106 WORDCAT: 19, 93, 105–106 BINDTEXT: 18–21 BINDWIN: 18–20 OUTPUT: 19, 99, 102, 106 OTHERHASH struct hash **hashtable: 17–19, 106 HASHSIZE: 17–18, 106 voidinithash(): 17, 187
17
8 Modul hash
Program kraluk
25: for(i=0; i
Funkce hashfunc přidělí ke klíči hashovací hodnotu, tj. index do pole hashtable. Protože klíč je v našem případě dvojice [typ, slovo], má funkce odpovídající parametry typ, s. hash.c 32: static int hashfunc (int typ, char *s) // Spocita cislo ze stringu 33: { 34: int i, vysledek; 35: 36: vysledek=typ*5; 37: for(i=0; s[i]; i++) 38: vysledek = (2*vysledek+(unsigned char)s[i])%HASHSIZE; 39: return vysledek; 40: }
Funkce hash_add pracuje ve dvou módech: Je-li parametr informace roven NULL, pak vymaže ze slovníku údaj týkající se klíče [typ,s] (pokud takový klíč neexistuje, jinak v tomto módu nedělá nic). Je-li informace různá od NULL, pak je ukazatelem na hodnotu, kterou funkce přidělí klíči [typ,s]. Pokud v takovém případě ve slovníku daný klíč existuje, jeho hodnota se přepíše novou hodnotou, jinak se založí do slovníku nová dvojice [klíč,hodnota]. hash.c 44: void hash_add (int typ, char *s, kq_pin *informace) 45: // Prida do hashe dalsi policko, pripadne ho smaze. (pokud informace==NULL) 46: { 47: /* 48: **pom je odkaz na pointer na policko hashe. Je to dvojpointer, abych nemusel 49: rozlisovat, jestli jsem na zacatku hashoveho radku nebo uz uprostred. 50: *pomo je ciste pomocna promenna pri odstraneni policka. 51: */ 52: struct hash **pom, *pomo; 53: 54: for(pom = &hashtable[hashfunc(typ,s)]; *pom; pom = &((*pom)->next)) // Prochazim hashovy radek. 55: if((typ == (*pom)->typ) && !strcmp((*pom)->string, s)){ 56: // Skoncim, kdyz najdu stejny typ i string. 57: uklid(*pom); // vycistim hashove policko 58: if(informace) (*pom)->informace = *informace; // Je-li podavana informace, dosadim ji tam 59: else{ // Je-li podavan NULL, zrusim policko: 60: pomo = *pom; 61: *pom = pomo->next; 62: free(pomo->string); 63: free(pomo); 64: } 65: return; 66: } 67: 68: // V hashi jsem dany typ+string nenasel, takze zalozim novy: 69: 70: if(!informace) return; 71: 72: *pom = (struct hash *)mymalloc(sizeof(struct hash)); 73: (*pom)->typ = typ; 74: (*pom)->string = dupstr(s); 75: (*pom)->informace = *informace; 76: (*pom)->next = NULL; 77: }
Při přepisování nebo mazání původní informace je někdy třeba odallokovat její pointer nebo vypsat varování v závislosti na typu. To řeší funkce uklid. hash.c 12: static void uklid (struct hash *h) 13: { 14: if(h->typ == BINDTEXT || h->typ == BINDWIN) free(h->informace.u.p); int hashfunc(): 18–19
void hash_add(): 18, 20, 93–94, 102, 105
18
void uklid /*hash*/ (): 17–18
9 Modul bindings
Program kraluk
15: if(h->typ == WORD) warning("podruhe ukladane slovo \"%s\" do hashe", h->string); 16: if(h->typ == WORDCAT) warning("podruhe ukladana kategorie \"%s\" do hashe", h->string); 17: if(h->typ == OUTPUT) warning("podruhe ukladany output \"%s\" do hashe", h->string); 18: }
Konečně funkce hash_find má parametr [typ,s], tedy klíč, a vrátí ukazatel na hodnotu, pokud úspěšně klíč ve slovníklu našla. Jestliže klíč ve slovníku není, vrátí NULL. hash.c 81: kq_pin *hash_find (int typ, char *s) 82: // Vyhleda zadany typ+string a vrati prislusnou informaci. 83: { 84: struct hash *pom; 85: 86: for(pom = hashtable[hashfunc(typ,s)]; pom; pom = pom->next) // Prochazim hashovy radek. 87: if(typ == pom->typ && !strcmp(pom->string, s)) return &(pom->informace); 88: 89: return NULL; // Pozadovany typ+string jsem nenasel. 90: } 91:
9 Modul bindings Tento modul řeší klávesové zkratky, nepodporuje však modifikační klávesy Shift, Ctrl, . . . Jediné, co tento modul tedy při zmáčknutí klávesy udělá, je, že se podívá do hashe, jestli tam je pod názvem dané klávesy nějaká akce. Akce pro klávesové zkratky jsou ukazatelem na strukturu keybind. bindings.h 1: struct keybind{ 2: void (*funkce)(); 3: kq_pin parametr; 4: };
Tato struktura má jen dvě položky. Funkci, která se spustí, a parametr, který se funkci předá. Hash má ovšem dva typy pro klávesové zkratky. Pokud je aktivní rámeček, kam se píše text (okrajtext je true), je použit typ BINDTEXT. Jinak je použit typ hashe BINDWIN. Funkce dobind dostane string a pokusí se podle něj provést klávesovou zkratku. Pokud se to povede, vrátí true, jinak vrátí false. bindings.c 147: char dobind (char *s) 148: { 149: struct keybind *b; 150: kq_pin *p; 151: 152: if(okrajtext) p = hash_find(BINDTEXT, s); 153: else p = hash_find(BINDWIN, s); 154: if(!p) return 0; 155: if(p->typ != PINPOINTER){ 156: warning("Klavesova zkratka ma spatny typ."); 157: return 0; 158: } 159: b=p->u.p; 160: spustsparem(b->funkce, &(b->parametr)); 161: return 1; 162: }
Funkce addbind přidá klávesovou zkratku do hashe, přičemž dostane typ hashe, potom název klávesy, pak funkci, která se má provést, a nakonec parametr typu kq_pin. bindings.c 127: void addbind (int typ, char *s, void (*funkce)(), 128: kq_pin parametr) 129: { 130: struct keybind *b; 131: kq_pin p; 132: 133: b=(struct keybind *)mymalloc(sizeof(struct keybind)); kq_pin hash_find(): 19, 81, 93, 99, 102–103 void addbind(): 19–21
struct keybind: 19
19
char dobind(): 19, 25, 120
9 Modul bindings 134: 135: 136: 137: 138: }
Program kraluk
b->funkce = funkce; b->parametr = parametr; p = pinpointer(b); hash_add(typ, s, &p);
Funkce addgbind přidá také klávesovou zkratku, ale nedostane typ hashe, protože klávesová zkratka uložená touto funkcí bude fungovat bez závislosti na tom, zda je aktivní hrací okno nebo řádek textu. Funguje to jednoduše tak, že tato funkce zavolá dvakrát funkci addbind. bindings.c 140: void addgbind (char *s, void (*funkce)(), 141: kq_pin parametr) 142: { 143: addbind(BINDWIN, s, funkce, parametr); 144: addbind(BINDTEXT, s, funkce, parametr); 145: }
Všechny klávesové zkratky uloží do hashe funkce initbindings. bindings.c 58: void initbindings () 59: { 60: addgbind("F1", popup_help, pinpointer("_help")); 61: addgbind("F2", gsave, pinnull); 62: addgbind("F3", gload, pinnull); 63: addgbind("F4", grestart, pinnull); 64: addgbind("F5", zmenFPS, pinint(1)); 65: addgbind("F6", zmenFPS, pinint(-1)); 66: addgbind("F7", zmenratio, pinint(-1)); 67: addgbind("F8", zmenratio, pinint(1)); 68: addgbind("F9", ukazinv, pinnull); 69: addgbind("F10", popup_help, pinpointer("_about")); 70: addgbind("F11", fullscreen, pinnull); 71: addgbind("F12", zobrazjazyky, pinnull); 72: addgbind("Return", text_enter, pinnull); 73: addgbind("KP_Enter", text_enter, pinnull); 74: 75: addbind(BINDWIN, "Escape", kql_exit, pinnull); 76: 77: addbind(BINDWIN, "BackSpace", zkoumejhist, pinint(1)); 78: addbind(BINDWIN, "KP_End", zmensmer, pinint(LEDO)); 79: addbind(BINDWIN, "KP_1", zmensmer, pinint(LEDO)); 80: addbind(BINDWIN, "KP_Down", zmensmer, pinint(DOLU)); 81: addbind(BINDWIN, "KP_2", zmensmer, pinint(DOLU)); 82: addbind(BINDWIN, "Down", zmensmer, pinint(DOLU)); 83: addbind(BINDWIN, "KP_Next", zmensmer, pinint(PRADO)); 84: addbind(BINDWIN, "KP_3", zmensmer, pinint(PRADO)); 85: addbind(BINDWIN, "KP_Left", zmensmer, pinint(VLEVO)); 86: addbind(BINDWIN, "KP_4", zmensmer, pinint(VLEVO)); 87: addbind(BINDWIN, "Left", zmensmer, pinint(VLEVO)); 88: addbind(BINDWIN, "KP_Right", zmensmer, pinint(VPRAVO)); 89: addbind(BINDWIN, "KP_6", zmensmer, pinint(VPRAVO)); 90: addbind(BINDWIN, "Right", zmensmer, pinint(VPRAVO)); 91: addbind(BINDWIN, "KP_Home", zmensmer, pinint(LENA)); 92: addbind(BINDWIN, "KP_7", zmensmer, pinint(LENA)); 93: addbind(BINDWIN, "KP_Up", zmensmer, pinint(NAHORU)); 94: addbind(BINDWIN, "KP_8", zmensmer, pinint(NAHORU)); 95: addbind(BINDWIN, "Up", zmensmer, pinint(NAHORU)); 96: addbind(BINDWIN, "KP_Prior", zmensmer, pinint(PRANA)); 97: addbind(BINDWIN, "KP_9", zmensmer, pinint(PRANA)); 98: 99: addbind(BINDWIN, "Tab", prepniokraj, pinint(1)); 100: addbind(BINDTEXT, "Tab", prepniokraj, pinint(0)); 101: 102: addbind(BINDTEXT, "Delete", (void (*)())delete, pinint(0)); 103: addbind(BINDTEXT, "KP_Delete", (void (*)())delete, pinint(0));
void addgbind(): 20
void initbindings(): 20, 187
20
9 Modul bindings 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: }
Program kraluk
addbind(BINDTEXT, "BackSpace", (void (*)())delete, pinint(1)); addbind(BINDTEXT, addbind(BINDTEXT, addbind(BINDTEXT, addbind(BINDTEXT, addbind(BINDTEXT, addbind(BINDTEXT, addbind(BINDTEXT, addbind(BINDTEXT,
"Left", "KP_Left", "Right", "KP_Right", "Home", "KP_Home", "End", "KP_End",
posunkursor, posunkursor, posunkursor, posunkursor, posunkursor, posunkursor, posunkursor, posunkursor,
pinint(0)); pinint(0)); pinint(1)); pinint(1)); pinint(2)); pinint(2)); pinint(3)); pinint(3));
addbind(BINDTEXT, addbind(BINDTEXT, addbind(BINDTEXT, addbind(BINDTEXT, addbind(BINDTEXT, addbind(BINDTEXT, addbind(BINDTEXT, addbind(BINDTEXT,
"Down", "KP_Down", "Up", "KP_Up", "Next", "KP_Next", "Prior", "KP_Prior",
zkoumejhist, zkoumejhist, zkoumejhist, zkoumejhist, zkoumejhist, zkoumejhist, zkoumejhist, zkoumejhist,
pinint(0)); pinint(0)); pinint(1)); pinint(1)); pinint(2)); pinint(2)); pinint(3)); pinint(3));
addbind(BINDTEXT, "Escape",
text_escape, pinnull);
Dále v tomto modulu mám funkce, které přímo souvisí s některými klávesovými zkratkami. Funkce grestart vyskočí s oknem s labelíkem _restart? a v případě, že toto okno není zrušeno klávesou Escape, restartuje hru. bindings.c 24: static void grestart () 25: { 26: if(popup_info("_restart?")) kql_restart(); 27: }
Funkce popup_help funguje stejně jako funkce popup_info, ale narozdíl od ní je typu void. bindings.c 29: static void popup_help (char *label) 30: { 31: popupstring(DEF_POP_SIRKA, DEF_POP_VYSKA, DEF_POP_X, DEF_POP_Y, outputstring(label, NULL), 1); 32: }
Nakonec tu mám funkci zmensmer. Tato funkce dostane jeden z možných směrů: NAHORU, DOLU, VLEVO, VPRAVO, LENA, PRANA, LEDO, PRADO. Podle toho pak postavě ovlpost přiřadím správné položky xx a yy. Pokud už ovlpost jde tím směrem, kterým by měla jít podle směru, který funkce zmensmer dostala, tak ji funkce zmensmer zastaví. V případě, že ovlpost == NULL, funkce zmensmer neudělá nic. bindings.c 34: static void zmensmer (int smer) 35: { 36: int xx, yy; 37: 38: if(!ovlpost) return; 39: 40: if(smer == LENA || smer == VLEVO || smer == LEDO) xx = -1; 41: else if(smer == PRANA || smer == VPRAVO || smer == PRADO) xx = 1; 42: else xx = 0; 43: 44: if(smer == LENA || smer == NAHORU || smer == PRANA) yy = -1; 45: else if(smer == LEDO || smer == DOLU || smer == PRADO) yy = 1; 46: else yy = 0; 47: 48: if(xx == ovlpost->xx && yy == ovlpost->yy){ 49: ovlpost->xx = 0; 50: ovlpost->yy = 0; 51: } 52: else{ 53: ovlpost->xx = xx; void grestart /*bindings*/ (): 20–21 void popup_help /*bindings*/ (): 20–21 void zmensmer /*bindings*/ (): 20–21 kq_postava *ovlpost: 21–22, 159, 185, 190, 204, 211, 215–217, 219, 221–224, 232, 238
21
10 Modul X
Program kraluk
54: ovlpost->yy = yy; 55: } 56: }
10 Modul X Tento modul načítá hlavičkové soubory Xlibu, které jsou potřeba, takže pokud jiný modul používá X-ovou funkci, měl by načíst X.h. X.h 3: 4: 5: 6: 7:
#include #include #include #include #include
<X11/Xlib.h> <X11/Xutil.h> <X11/Xos.h> <X11/Xlocale.h> <X11/extensions/shape.h>
Dále jsou zde proměnné, které s iXy souvisejí: X.h 11: 12: 13: 14: 15: 16:
Display *display; int screen; int display_sirka, display_vyska; unsigned int depth; GC text_gc, ggc; Window root;
Tyto proměnné zinicializuji ve funkci initX. X.c 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
void initX () /*******************************/ { char *display_name = NULL; if ((display=XOpenDisplay(display_name)) == NULL) error("cannot connect to X server %s", XDisplayName(display_name)); screen = DefaultScreen(display); display_sirka = DisplayWidth(display,screen); display_vyska = DisplayHeight(display,screen); root = RootWindow(display,screen); depth = DefaultDepth(display,screen); ggc = DefaultGC(display, screen); }
Potom tady mám funkci kreslianim, která pošle frontu příkazů X-serveru (každý frame). X.c 26: void kreslianim () 27: { 28: if(mengraf) XSync(display, 0); 29: mengraf = 0; 30: }
Abych neposílal X-serveru zbytečně prázdnou frontu událostí (nevím, zda to má funkce XSync z Xlibu ošetřené), tak tato funkce pošle onu frontu jen v případě, že proměnná mengraf je nastavená na true. Proměnná mengraf by se tedy měla nastavit na true vždy po volání X-ových funkcí. X.h 20: char mengraf;
11 Modul keyboard Pro správné zacházení se znaky čtenými z klávesnice, je třeba zinicializovat input metodu a input context (viz Xlib Programming Manual). To udělám funkcí initklav. Input context je uložen do lokální proměnné xic. Display *display: 22–23, 25, 34–37, 40–46, 48–50, 109–111, 119–123, 125–126, 147, 163, 186, 188–189 int screen: 22, 40, 46, 121, 125, 147, 186 int display_sirka: 22, 39, 43 int display_vyska: 22, 39, 43 unsigned int depth: 22, 35 GC text_gc: 40, 109–111, 189 GC ggc: 22, 42, 49 Window root: 22, 35, 40 void initX(): 22, 187 void kreslianim(): 22, 24 char mengraf: 22, 25, 41–42, 45–46, 48–50, 66, 115, 120, 123, 147 void initklav(): 23, 188 XIC xic /*keyboard*/ : 23
22
11 Modul keyboard
Program kraluk keyboard.c
8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55:
static XIC xic = NULL; void initklav () // Zinicializuje cteni z klavesnice. { XIM xim; char *imvalret; XIMStyles *xim_styles; XIMStyle xim_style = 0; int i; xim = XOpenIM (display, NULL, NULL, NULL); if (xim == NULL) { warning("openning of input method failed"); } else{ imvalret = XGetIMValues (xim, XNQueryInputStyle, &xim_styles, NULL); if (imvalret != NULL || xim_styles == NULL) { warning("input method doesn’t support any styles"); } if (xim_styles) { xim_style = 0; for (i = 0; i < xim_styles->count_styles; i++) { if (xim_styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) { xim_style = xim_styles->supported_styles[i]; break; } } if (xim_style == 0) { warning("input method doesn’t support the style we support"); } XFree (xim_styles); } } if (xim && xim_style) { xic = XCreateIC (xim, XNInputStyle, xim_style, XNClientWindow, textwin, XNFocusWindow, textwin, NULL); if (xic == NULL) { warning("Creating of XIC failed"); } } }
Poté, co mám klávesnici zinicializovanou, mohu převést událost na znak, co má být napsán, funkcí xkeyznak. Pokud tato událost nemůže vykreslit znak, funkce vrátí nulu. Jinak vrátí přislušný znak. keyboard.c 57: char xkeyznak (XEvent *e) 58: { 59: int pocetznaku; 60: char str[8]; 61: XKeyEvent *event = &(e->xkey); 62: 63: if(xic){ 64: if(XFilterEvent (e, textwin)) return 0; 65: pocetznaku = XmbLookupString(xic, event, str, 8, NULL, NULL); 66: } 67: else pocetznaku = XLookupString (event, str, 8, NULL, NULL); 68: // Nahradni varianta, kdyz se nenacte xic (zcela nefunguje) 69: char xkeyznak(): 23, 25, 120, 164
23
12 Modul loop 70: 71: 72: 73: 74: }
Program kraluk
// Zkontroluji, zda jde skutecne o znak: if(pocetznaku != 1) return 0; if(isprint(str[0])) return str[0]; return 0;
12 Modul loop Modul loop obsahuje funkci loop() a pár dalších s kterými tato funkce souvisí. Funkce loop je spuštěná na startu a od té doby běží a spouští další funkce. Během jednoho svého cyklu tato funkce udělá následující: 1) 2) 3) 4)
Zpracuje nové události. Provede timery a posune je o jedničku. Provede grafické změny. Počká předem určený čas.
V tom čekání je malý háček, protože hardware není schopný čekat tak dlouho, jak chci, ale jen po násobcích určitého minimálního času. Abych tedy nebyl omezen nějakou maximální rychlostí, kontroluji každý frame, jak se liší čas, který měl čekat a čas, který ve skutečnosti čekal. Pokud čekal x-krát delší (x > 1) dobu nez měl, pustím bez čekání x framů. Například pokud po něm chci, aby čekal 2 sekundy a on čeká 10 nebo 11 sekund, přeskočím čtyřikrát žádost o čekání. Pokud by ale ve skutečnosti čekal jednu nebo tři sekundy, nic nepřeskakuji. Není to sice zcela přesné, ale alespoň nejsem omezen maximální rychlostí. loop.c 139: void loop () 140: /**********/ 141: { 142: struct timeval tv, ocas, ncas; 143: long int i = 0; 144: long int opakovani = 0; 145: 146: // popup_sl("zkouska", (void (*)(char *))puts); 147: 148: gettimeofday(&ocas, NULL); 149: for(;;){ 150: cekalose = 0; 151: 152: udalosti(); // zpracovavam udalosti 153: 154: dotimers(); // Provedu timery 155: if(prvtimer) prvtimer-> zbyva--; //a posunu je o jednicku 156: 157: updateposts(); // provedu graficke 158: kreslianim(); // zmeny 159: 160: if(opakovani) opakovani--; 161: 162: if(!opakovani){ 163: tv.tv_sec = vter; 164: tv.tv_usec = uvter; 165: select(0, NULL, NULL, NULL, &tv); // cekam 166: } 167: 168: i++; 169: gettimeofday(&ncas, NULL); 170: if(ocas.tv_sec < ncas.tv_sec){/* 171: printf("real FPS: %ld, ", i); 172: printf("real delay: %ld\n", (ncas.tv_sec-ocas.tv_sec)*1000000 173: + (ncas.tv_usec-ocas.tv_usec));*/ 174: i=0; 175: } void loop(): 24–25, 28, 187–188
24
12 Modul loop
Program kraluk
176: 177: if(!opakovani && !cekalose) 178: opakovani = 179: ((ncas.tv_sec-ocas.tv_sec)*1000000 + (ncas.tv_usec-ocas.tv_usec))/ 180: (vter*10000000 + uvter); 181: if(cekalose) opakovani = 0; 182: 183: ocas = ncas; 184: } 185: }
Do globální proměnné cekalose uložím true, pokud je vhodné přeskakování framů přerušit, Další frame je do proměnné cekalose opět uložen false. Na true se nastavuje například, když měním rychlost nebo přepnu do textového módu. Do lokalní proměnné opakovani ukládám, kolikrát ještě chci přeskočit čekání. Pokud nic nepřeskakuji, je v opakovani nula. Ve funkci loop volám funkci udalosti pro zpracování událostí. Tato funkce projde všechny zafrontěné události a pokud je pak aktivní okno s textovým vstupem, nevypne se, a čeká na události, dokud se opět nezaktivní hlavní okénko s obrázky. loop.c 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135:
static void udalosti () /*********************/ { XEvent report; KeySym ks; char *ksname, ch; while (okrajtext || XEventsQueued(display, QueuedAfterReading)){ if(okrajtext){ cekalose = 1; updateposts(); } XNextEvent(display, &report); // seberu udalost ze fronty nebo na ni cekam switch (report.type){ case Expose: // Pri odkryti textu redrawtext(); // je treba ho prekreslit. if(!okrajtext) mengraf = 1; break; case ButtonPress: // Pri zmacknuti tlacitka na mysi popup_info("_help"); // se ukaze napoveda break; case KeyPress: // Pri zmacknuti klavesy XLookupString (&report.xkey, NULL, 0, &ks, NULL); if (ks != NoSymbol && (ksname = XKeysymToString (ks)) && dobind(ksname)) break; // zkusim spustit klavesovou zkratku ch = xkeyznak(&report); if(ch) pripisznak(ch); // nebo alespon pripsat zmacknuty znak do spodniho radku } } }
Čas, který chci čekat, je uložený v proměnných vter a uvter. V proměnné vter je počet sekund, který se má čekat a v proměnné uvter zbyvající počet mikrosekund. Tento čekající čas se dá změnit pomocí funkce setdelay, která dostane počet sekund a mikrosekund. Tento čas vloží do proměnných vter a uvter, přižemž nejprve převede parametry do jednoho čísla a pak opět rozloží. loop.c 86: void setdelay (int vteriny, int mikro) 87: /***********************************/ 88: { char cekalose: 24–26, 34, 119, 123, 165 : 24–26 int uvter /*loop*/ : 24–26
void udalosti /*loop*/ (): 24–25 void setdelay(): 25–27
25
int vter /*loop*/
12 Modul loop 89: 90: 91: 92: 93: 94: 95: 96: 97: }
Program kraluk
long int cas; cas = mikro + vteriny*1000000; if(cas>0){ vter = cas/1000000; uvter = cas%1000000; } cekalose = 0;
Pomocí funkce setFPSs vytvořím pole FPSs rychlostí, které budou ve hře dostupné. Tato funkce má proměnný počet parametrů, takže kompilátor nepozná, jaký je typ parametrů. Je proto třeba u každého parametru (kromě prvního) zdůraznit, že je typu double, například tím, že se za něj napíše desetiná tečka. Seznam parametrů je ukončen nulou a záporný parametr bude načten jako aktuální rychlost (FPS). V proměnné aktuFPS je index do pole FPSs pro aktuální rychlost. Proměnná maxFPS udává index na poslední políčko pole FPSs tedy jeho délka minus jedna. Tato funkce by měla být spuštěna před funkcí kql_init. loop.c 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62:
static double *FPSs = NULL; void setFPSs (double prvni, ...) { va_list vl; double d; if(FPSs) warning("rychlosti uz byly definovany"); maxFPS = 0; va_start(vl, prvni); for(d=prvni; d; d = va_arg(vl, double)){ maxFPS++; } va_end(vl); FPSs = malloc(maxFPS*sizeof(double)); aktuFPS = maxFPS = -1; va_start(vl, prvni); for(d=prvni; d; d = va_arg(vl, double)){ maxFPS++; if(d<0){ if(aktuFPS >= 0) warning("aktualni FPS je vicenasobne"); aktuFPS = maxFPS; d = -d; } FPSs[maxFPS] = d; } va_end(vl); if(aktuFPS == -1){ warning("nenalezeno aktualni FPS"); aktuFPS = 0; } setdelay(0, 1000000/FPSs[aktuFPS]); }
Pro změnu aktuální rychlosti se dá použít funkce zmenFPS. Jejím parametrem je hodnota, která se přičte k proměnné aktuFPS. loop.c 66: void zmenFPS(int oco) 67: { 68: int i;
void setFPSs(): 26, 187, 190 double FPSs: 26–27 int aktuFPS: 26–27, 160–162 int maxFPS: 26–27, 161–162 void zmenFPS(): 20, 26, 161–162
26
13 Modul timer 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: }
Program kraluk
if(!FPSs){ warning("nenacteny rychlosti"); return; } i = aktuFPS+oco; if(i<0) i=0; if(i>maxFPS) i = maxFPS; if(i != aktuFPS) setdelay(0, 1000000/FPSs[i]); aktuFPS = i; printf("FPS: %f\n", FPSs[i]);
13 Modul timer Základní představa timeru je jakýsi budík, který po předem určeném čase zazvoní, čili spustí určitou funkci. Obvykle (jinde než v tomto programu) se timeru zadává počet sekund a milisekund, jakožto čas, za který se má spustit. Tento přístup však není přesný, jelikož i výpočet trvá nějakou dobu a navíc chci hru někdy zpomalovat nebo zrychlovat. Tady se tedy timeru přiřadí počet framů. Timer se deklaruje jako ukazatel na datový typ kq_timer. Definice tohoto datového typu vypadá následovně: timer.h 3: struct kq_timer{ 4: kq_timer *next; 5: 6: void (*funkce)(); 7: kq_pin parametr; 8: 9: unsigned int zbyva; 10: float priorita; 11: 12: int opakovani; 13: unsigned int cas; 14: 15: char pause; 16: char lokalni; 17: 18: int Cislo; 19: };
S tímto datovým typem se dá manipulovat pomocí funkcí: timer.h 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48:
void dotimers(); int zjistitimer(kq_timer *tim); void zmentimer(kq_timer *tim, int cas, float priorita); void pausetimer(kq_timer *tim); void unpausetimer(kq_timer *tim); void deleteltimers(); void deleteAtimers(); kq_timer *vytvortimer(void (*funkce)(), kq_pin parametr, int cas, float priorita, int opakovani, char lokalni, char pause); void znictimer(kq_timer *tim); void vypistimer(kq_timer *tim); void vypistimery();
První dvě položky struktury určují, co se má stát při „zazvoněníÿ timeru. Spustí se funkce funkce s daným parametrem podle kq_pin, pin. kq_timer: 7, 27–33, 63, 65, 132, 136, 138–141, 143, 145–146, 148, 154, 167
27
13 Modul timer
Program kraluk
Poté, co timer „zazvoníÿ, se s ním mohou stát dvě věci. Buď zmizí (smaže se) a už se s ním nedá nic dělat nebo se pustí znova. V položce opakovani je počet „zazvoněníÿ, které timeru ještě zbývají. Je-li opakovani záporné nebo nulové, bude se timer opakovat pořád. Položka cas udává, na jaký čas se má timer při opakování zpátky nastavit. Položky opakovani i cas se dají bez problémů měnit. Měníte-li však timer, co je právě spuštěný, je dobré vědět, co přesně dělá funkce dotimers(). Funkce dotimers spustí timery, co jsou právě na řadě. Ukazatel na právě spuštěný timer přitom uloží do globální proměnné aktutimer. timer.c 19: kq_timer *aktutimer = NULL;
Není-li spuštěn žádný timer, je aktutimer roven NULL. Rovněž však může aktutimer nabývat hodnoty NULL v případě, že byl smazán (sám sebou). Každý timer, který není aktutimer, je buď v seznamu puštěných nebo zapausovaných timerů. Ke každému puštěnému timeru, který není aktutimer, se dá dostat přes položky next z timeru prvtimer, k zapausovanému timeru se dá dostat z timeru pausedtimers. timer.c 23: kq_timer *prvtimer = NULL; 24: kq_timer *pausedtimers = NULL;
Zapausované timery jsou jednoduše (zásobníkově) řazeny za sebe a v položce zbyva zapausovaného timeru je zbývající čas. Stejně tak je zbývající čas timeru aktutimer v aktutimer->zbyva. Seznam puštěných timerů je setřízen od toho, co se spustí nejdříve, po ten, co se spustí nejpozději. Závisí to tedy na zbývajícím čase a prioritě. V položce zbyva puštěného timeru je rozdíl zbývajícího času toho a předchozího timeru. Ke spočtení zbývajícího času spuštěného timeru je třeba sečíst položky zbyva timerů od timeru prvtimer po daný timer (včetně), což dělá funkce zjistitimer. timer.c 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118:
int zjistitimer (kq_timer *tim) /*****************************/ { int cas; kq_timer *pom; if(tim->pause || tim == aktutimer) return tim->zbyva; cas=0; for(pom = prvtimer; tim != pom; pom = pom->next){ if(!pom){ warning("zjistitimer: timer nenalezen\n"); return -1; } cas += pom->zbyva; } return cas + tim->zbyva; }
Výhodou takového uspořádání ale je, že pro posunutí ručičky všech timerů stačí odečíst jedničku od zbyva v prvtimeru, to se děje ve funkci loop. Příklad situace timerů je na obrázku:
kq_timer aktutimer: 28–33, 139–140, 168, 222, 226–227, 229, 234, 236, 238–239 zjistitimer(): 27–28, 30, 231
28
int
13 Modul timer
0
Program kraluk
1
2
4
3
aktutimer
4
pausedtimers
5
6
7
NULL
3 6
0 2 4
0
NULL
prvtimer
0
0
1
1
3
1
2
3
2
5
4
6
NULL
7
Pro manipulaci s timery zde jsou statické funkce zaradtimer a vyradtimer. Tyto funkce podle položky pause zařadí/vyřadí timer do/z příslušného seznamu. O timeru aktutimer tyto funkce nepřemýšlí. timer.c 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59:
static void zaradtimer (kq_timer *tim, int cas) /*********************************************/ { kq_timer **pom; if(tim->pause){ tim->zbyva = cas; tim->next = pausedtimers; pausedtimers = tim; return; } for(pom = &prvtimer;; pom = &(*pom)->next){ // vyhledam vhodne misto if(!*pom) break; cas -= (*pom)->zbyva; // cas se nakonec ulozi do zbyva if(cas < 0) break; if(cas == 0 && tim->priorita >= (*pom)->priorita) break; } if(*pom){ cas += (*pom)->zbyva; // cas jsem prestrelil (*pom)->zbyva -= cas; // upravim zbyva v nasledujicim timeru } tim->zbyva = cas; tim->next = *pom; *pom = tim; } static void vyradtimer (kq_timer *tim) /************************************/ {
void zaradtimer /*timer*/ (): 29–31, 33
void vyradtimer /*timer*/ (): 29, 31, 33
29
13 Modul timer 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: }
Program kraluk
kq_timer **pom; if(tim->pause) pom = &pausedtimers; else pom = &prvtimer; for(; *pom != tim; pom = &(*pom)->next) if(!*pom){ warning("vyradtimer(): timer nenalezen"); return; } *pom = tim->next; if(tim->next && !tim->pause) tim->next->zbyva += tim->zbyva;
Funkce dotimers provede s timerem, který „zazvonilÿ toto: 1) Uloží timer do globálního timeru aktutimer, nastaví do zbývajícího času hodnotu z položky cas a není-li položka opakovani záporná, zmenší ji o jedničku. 2) Spustí patřičnou funkci 3) Pokud je položka opakovani nulová, smaže timer, jinak ho vrátí mezi ostatní timery. timer.c 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290:
void dotimers() /*************/ { while(prvtimer && !prvtimer->zbyva){ // Vyradim timer ze seznamu: aktutimer = prvtimer; prvtimer = prvtimer->next; aktutimer->zbyva = aktutimer->cas; aktutimer->next = NULL; if(aktutimer->opakovani >= 0) aktutimer->opakovani--; // Spustim ho: spustsparem(aktutimer->funkce, &aktutimer->parametr); // Vratim ho zpatky nebo smazu: if(aktutimer){ // timer se mohl sam smazat if(!aktutimer->opakovani) free(aktutimer); // Timer uz se provedl, kolikrat mel. else zaradtimer(aktutimer, aktutimer->zbyva); } } aktutimer = NULL; }
Funkce zjistitimer spočítá počet framů, za který se timer pustí. K tomu využije položku zbyva v kq_timer. Jelikož se timerům nedává reálný, ale celočíselný čas, může se snadno stát, že v jednom „zazvoníÿ více timerů najednou. V takovém případě se funkce timerů pouští postupně od timeru s nejvyšší hodnotou položky priorita po timer s nejnižší hodnotou položky priorita. Jak zbývající čas, tak prioritu je třeba měnit funkcí zmentimer. Tato funkce zbývající čas nahradí hodnotou z parametru cas, ale nepřepíše položku cas. Kromě toho ještě přepíše položku priorita. timer.c 122: void zmentimer (kq_timer *tim, int cas, float priorita) 123: /*****************************************************/ 124: { 125: tim->priorita = priorita; 126: if(tim->pause || tim == aktutimer) void dotimers(): 24, 27–28, 30
void zmentimer(): 27, 30, 231, 238–239
30
13 Modul timer
Program kraluk
127: tim->zbyva = cas; 128: else{ 129: vyradtimer(tim); 130: zaradtimer(tim, cas); 131: } 132: }
Dále je možné timer zapausovat funkcí pausetimer a odpausovat funkcí unpausetimer. Informace, jestli je timer zapausován, je v položce pause (0 = odpausován, 1 = zapausován). Zapausovaný timer, kterému nezbývá žádný frame, se spustí až po odpausování. Funkce pausetimer práci se seznamy řeší samostatně. Při vyřazení totiž musí spočítat zbývající čas a zařazení k zapausovaným timerům je příliš snadné na to, aby na to byla volána funkce. timer.c 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171:
void pausetimer (kq_timer *tim) /********************************/ { kq_timer **pom; if(tim->pause) return; tim->pause = 1; if(tim == aktutimer) return; if(tim->next) tim->next->zbyva += tim->zbyva; for(pom = &prvtimer; *pom != tim; pom = &(*pom)->next){ if(!*pom){ warning("pausetimer(): timer nenalezen\n"); return; } tim->zbyva += (*pom)->zbyva; } *pom = tim->next; tim->next = pausedtimers; pausedtimers = tim; } void unpausetimer(kq_timer *tim) /********************************/ { if(!tim->pause) return; if(tim == aktutimer){ tim->pause = 0; return; } vyradtimer(tim); tim->pause = 0; zaradtimer(tim, tim->zbyva); }
Poslední položka timeru je lokalni. Podle ní se řídí funkce deleteltimers, která je spuštěna při přechodu na jiné políčko. Položka lokalni může nabývat tří hodnot: • Nula znamená, že je timer globální, čili funkce deleteltimers s ním nic neprovede. • Záporné číslo znamená, že ten timer funkce deleteltimers zapausuje, je-li již zapausován, nic se s ním neděje. • Kladné číslo znamená, že ten timer funkce deleteltimers smaže. Položku lokalni je možné zcela bez problémů měnit. timer.c 185: void deleteltimers() 186: /******************/ 187: { void pausetimer(): 27, 31, 66, 226 deleteltimers(): 27, 31, 173
void unpausetimer(): 27, 31, 66, 227
31
void
13 Modul timer 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: }
Program kraluk
kq_timer **pom, *pomo, *pomoc; int i; // Prochazim zapausovane timery: for(pom = &pausedtimers;; pom = &pomo->next){ for(pomo = *pom; pomo && pomo->lokalni > 0; pomo = pomoc){ pomoc = pomo->next; free(pomo); } *pom = pomo; if(!pomo) break; } // Prochazim spustene timery. i=0; for(pom = &prvtimer; (pomo = *pom); pom = &pomo->next){ i += pomo->zbyva; for(; pomo && pomo->lokalni; pomo = pomoc){ pomoc = pomo->next; if(pomoc){ i += pomoc->zbyva; pomoc->zbyva += pomo->zbyva; pomo->zbyva += i - pomoc->zbyva; } else pomo->zbyva=i; if(pomo->lokalni > 0) free(pomo); else{ pomo->pause = 1; pomo->next = pausedtimers; pausedtimers = pomo; } } *pom = pomo; if(!pomo) break; } // Zkontroluji aktualni timer: if(aktutimer && aktutimer->lokalni){ if(aktutimer->lokalni < 0) aktutimer->pause = 1; else{ free(aktutimer); aktutimer = NULL; } }
Pro načítání pozice je třeba smazat všechny timery. To dělá funkce deleteAtimers. timer.c 240: void deleteAtimers() 241: /******************/ 242: { 243: kq_timer *pom; 244: 245: while(prvtimer){ 246: pom = prvtimer->next; 247: free(prvtimer); 248: prvtimer = pom; 249: } 250: while(pausedtimers){ 251: pom = pausedtimers->next; 252: free(pausedtimers); 253: pausedtimers = pom; void deleteAtimers(): 27, 32, 148, 188
32
14 Modul pixmap
Program kraluk
254: } 255: if(aktutimer){ 256: free(aktutimer); 257: aktutimer = NULL; 258: } 259: }
Funkce vytvortimer založí nový timer a do každé položky struktury přiřadí příslušný parametr. Zbývající čas začíná na hodnotě cas. timer.c 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96:
kq_timer *vytvortimer (void (*funkce)(), kq_pin parametr, int cas, float priorita, int opakovani, char lokalni, char pause) /************************************************************************/ { kq_timer *tim; tim = (kq_timer *)mymalloc(sizeof(kq_timer)); tim->funkce = funkce; tim->parametr = parametr; tim->cas = cas; tim->priorita = priorita; tim->opakovani = opakovani; tim->lokalni = lokalni; tim->pause = pause; zaradtimer(tim, tim->cas); return tim; }
Funkce znictimer smaže timer. timer.c 175: 176: 177: 178: 179: 180: 181:
void znictimer(kq_timer *tim) /***************************/ { if(tim == aktutimer) aktutimer = NULL; else vyradtimer(tim); free(tim); }
Ještě jsou dostupné dvě funkce jakožto ladící tisky. Funkce vypistimer vypíše dostupné informace o daném timeru, funkce vypistimery pomocí funkce vypistimer vypíše všechny timery.
14 Modul pixmap Zde se načítají z XPM souboru obrázky pro zobrazení ve hře. K tomu je zapotřebí načíst další X-ové hlavičkové soubory: pixmap.h 3: #include <X11/xpm.h> 4: #include <X11/extensions/shape.h>
Základní funkce, která načítá XPM, je nactiXPM. Tato funkce přečte (spíše si nechá přečíst) soubor, který získá tak, že doleva připíše DATADIR a IMGDIR a doprava připíše IMGSUFFIX. Za normálních okolností tedy tento soubor hledá v adresáři s obrázky a automaticky k názvu připojí příponu .xpm. Z tohoto souboru vytvoří pixmapu (obrázek na straně serveru), kterou vrátí. Za parametrem filename následuje parametr, kam se má uložit ximage (obrázek na straně klienta), pak odkaz na pixmapu masky (čili kde je průhledno a kde ne) a odkaz na ximage masky. Tyto parametry (které jsou jen odkazem pro uložení něčeho) mohou nabývat hodnoty NULL, čímž dáváte najevo, že se o dané něco nezajímáte. Do pixmap jsou automaticky uloženy zvětšené obrázky podle globální proměnné ratio. kq_timer vytvortimer(): 27, 33, 65, 68, 73, 167, 207–208, 221–222, 224, 226, 229–236 void znictimer(): 27, 33, 65, 68, 73, 207, 217, 221–222, 226–227, 231, 234, 236, 238 void vypistimer(): 27, 33 void vypistimery(): 27 Pixmap nactiXPM(): 34, 36, 39, 41–42, 147 int ratio: 11, 20, 34–36, 38–39, 41–44, 46, 48–49, 147, 161–162, 186–187
33
14 Modul pixmap
Program kraluk pixmap.h
36: int ratio;
Pixmapy jsou tedy ratio-krát větší než ximage. Zdrojový kód funkce nactiXPM vypadá takto: pixmap.c 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113:
Pixmap nactiXPM (char *filename, XImage **xim, Pixmap *shape, XImage **xish) /*************************************************************************/ { Pixmap vysledek; XImage *ximage; XImage *shapeimage; char *fullname; // Prida ke jmenu cestu k obrazku: fullname = joinstrings(DATADIR, IMGDIR, filename, IMGSUFFIX,
NULL);
// Nactu image pomoci X-ove funkce: if(XpmReadFileToImage(display, fullname, &ximage, &shapeimage, NULL)) error("I can’t open \"%s\"", fullname); free(fullname); vysledek = None; // dosadim None, abych dal najevo, ze onu pixmapu nechci smazat rescalePixmap(ximage, &vysledek); // Vytvorim pixmapu barev. if(xim) *xim = ximage; // XImage barev vratim else XDestroyImage(ximage); // nebo odallokuji. if(shape){ *shape = None; rescalePixmap(shapeimage, shape); // Vytvorim pixmapu alfa kanalu } if(xish) *xish = shapeimage; // XImage alfa kanalu vratim else if(shapeimage) XDestroyImage(shapeimage); // nebo odalokuji return vysledek; }
Pro vytvoření zvětšené pixmapy z ximage jsem naprogramoval funkci rescalePixmap. Tato funkce má dva parametry: první je ten ximage a druhý odkaz na pixmapu. Poměr zvětšení si přečte z proměnné ratio. Pokud v pixmapě není None, funkce předpokládá, že se tam nalézá pixmapa s jiným poměrem zvětšení a tak ji uvolní z paměti. Jsou čtyři možnosti, jak tato funkce bude pracovat: a) Pokud ratio == 0, do pixmapy dosadí NULL. b) Pokud ratio > IMAGRAT, prochází ximage po řádcích a do nové pixmapy vykresluje po čtverečcích. Pokud je v řádku více stejných pixelů u sebe, jsou čtverečky vrámci ušetření síťového přenosu spojeny do obdélníčku. c) Pokud ratio == 1, jednoduše pošle ximage X-serveru. d) V ostatních případech si vytvoří pomocný ximage, do kterého to vyscaluje a pak tento pomocný ximage pošle X-serveru. pixmap.c 19: void rescalePixmap (XImage *ximage, Pixmap *pxm) 20: /*********************************************/ 21: { 22: XImage *ipom; 23: GC lgc; 24: int i,j,x,x2,y; 25: unsigned long pixel; 26: 27: if(*pxm) XFreePixmap(display, *pxm); // Neni-li pxm None, odallokuji to 28: if(ratio == 0 || !ximage){ 29: *pxm = None; 30: return; 31: } 32: cekalose = 1;
void rescalePixmap(): 34, 39, 46, 48, 147
int IMAGRAT: 11, 35
34
14 Modul pixmap 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: }
14.1
Program kraluk
// Pripravim novou pixmapu: *pxm = XCreatePixmap(display, root, ximage->width*ratio, ximage->height*ratio, ximage->depth); lgc = XCreateGC(display, *pxm, 0, NULL); if(ratio <= IMAGRAT){ if(ratio == 1){ // Pomer je 1:1 -> neni treba aplikovat scale: XPutImage(display, *pxm, lgc, ximage, 0, 0, 0, 0, ximage->width, ximage->height); XFreeGC(display, lgc); return; } ipom = XCreateImage (display, CopyFromParent, ximage->depth, ximage->format, ximage->xoffset, mymalloc(ximage->bytes_per_line*ratio* ximage->height*ratio), ximage->width*ratio, ximage->height*ratio, ximage->bitmap_pad, ximage->bytes_per_line*ratio); } for(y=0; y<ximage->height; y++) for(x=0; x<ximage->width; x++){ pixel = XGetPixel(ximage, x, y); // Pro kazdy pixel ze zdrojoveho obrazku if(ratio <= IMAGRAT) for(j=y*ratio; j<(y+1)*ratio; j++) for(i=x*ratio; i<(x+1)*ratio; i++) XPutPixel(ipom, i, j, pixel); // vykreslim ctverec do pomocneho ximage else{ // nebo vykreslim cely radek do pixmapy: for(x2 = x+1; x2<ximage->width && XGetPixel(ximage, x2, y) == pixel; x2++); XSetForeground(display, lgc, pixel); XFillRectangle(display, *pxm, lgc, x*ratio, y*ratio, ratio*(x2-x), ratio); x = x2-1; } } if(ratio <= IMAGRAT) XPutImage(display, *pxm, lgc, ipom, 0, 0, 0, 0, ipom->width, ipom->height); XFreeGC(display, lgc);
kq pixmap Pro spojení všech potřebných pixmap a ximage jsem vytvořil datový typ kq_pixmap. pixmap.h
13: struct kq_pixmap{ 14: Pixmap barvy; // pixmapa 15: Pixmap akanal; // pixmapa masky 16: 17: XImage *ibarvy; // ximage 18: XImage *ikanal; // ximage masky 19: 20: int scaled; 21: char lokalni; 22: char *nazev; 23: kq_pixmap *next; 24: unsigned int Cislo; 25: }; kq_pixmap: 7, 35–37, 39, 44–45, 48, 67, 70, 72, 74, 136–138, 141, 143–144, 146, 148, 150, 152, 167, 180, 186
35
14 Modul pixmap
Program kraluk
26: 27: kq_pixmap *prvpix;
Položka scale udává s jakým ratio byly pixmapy naposledy scalovány. Při změně rozlišení totiž přescaluji jenom viditelné pixmapy a ostatních se nedotknu. Položka lokalni udává, podobně jako u timerů či widgetů, zda má být pixmapa při přechodu na jiné políčko smazána (lokalni=True) nebo zachována (lokalni=False). Položka next určuje další pixmapu v seznamu, který začíná pixmapou prvpix. Pro přístup k šířce a výšce pixmapy využívám následující definice: pixmap.h 8: #define PIX_VYS ibarvy->height 9: #define PIX_SIR ibarvy->width
Potom například šířka pixmapy pix je pix->PIX_SIR. Tuto strukturu vytvořím a začlením do seznamu funkcí nactikqXPM. pixmap.c 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134:
kq_pixmap *nactikqXPM (char *filename, char lokalni) /******************************************************/ { kq_pixmap *vysledek; vysledek = (kq_pixmap*)mymalloc(sizeof(kq_pixmap)); vysledek->barvy = nactiXPM(filename, &vysledek->ibarvy, &vysledek->akanal, &vysledek->ikanal); vysledek->scaled = ratio; vysledek->lokalni = lokalni; vysledek->nazev = dupstr(filename); vysledek->next = prvpix; prvpix = vysledek; return vysledek; }
Pokud ji již nebudu používat, mohu ji uvolnit z paměti a smazat ze seznamu pomocí funkce freekqPixmap. pixmap.c 138: void freekqPixmap (kq_pixmap *pxm) 139: { 140: kq_pixmap **pom; 141: 142: for(pom = &prvpix; *pom && *pom != pxm; pom = &(*pom)->next); 143: if(!pom){ 144: warning("pixmapa nenalezena v seznamu"); 145: return; 146: } 147: 148: *pom = pxm->next; 149: free(pxm->nazev); 150: if(pxm->barvy) XFreePixmap(display, pxm->barvy); 151: if(pxm->akanal) XFreePixmap(display, pxm->akanal); 152: XDestroyImage(pxm->ibarvy); 153: XDestroyImage(pxm->ikanal); 154: free(pxm); 155: }
Pixmapy mám zařazené za sebou ze dvou důvodů. Abych je mohl ukládat a abych mohl smazat všechny lokální pixmapy. Toto mazání provádí funkce deletelpixmaps. pixmap.c 159: void deletelpixmaps () 160: { 161: kq_pixmap *oriprv, *pom; kq_pixmap *prvpix: 36–37, 139, 141, 143, 147, 178–180 PIX_VYS: 39, 42–43, 46, 49, 147, 186 PIX_SIR: 36, 39, 42–43, 46, 49, 147, 186 kq_pixmap *nactikqXPM(): 36, 72, 179, 186, 203, 205, 224, 228, 232, 234, 237–238 void freekqPixmap(): 36–37, 73, 186 void deletelpixmaps(): 36, 173
36
15 Modul window 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: }
Program kraluk
pom = oriprv = NULL; while(prvpix){ if(prvpix->lokalni){ freekqPixmap(prvpix); if(pom) pom->next = prvpix; } else{ pom = prvpix; if(!oriprv) oriprv = prvpix; prvpix = prvpix->next; } } prvpix = oriprv;
Také mohu smazat všechny pixmapy (při načítání pozice) funkcí deleteApixmaps pixmap.c 181: void deleteApixmaps () 182: { 183: kq_pixmap *pom; 184: 185: while(prvpix){ 186: pom = prvpix->next; 187: free(prvpix->nazev); 188: if(prvpix->barvy) XFreePixmap(display, prvpix->barvy); 189: if(prvpix->akanal) XFreePixmap(display, prvpix->akanal); 190: XDestroyImage(prvpix->ibarvy); 191: XDestroyImage(prvpix->ikanal); 192: free(prvpix); 193: prvpix = pom; 194: } 195: }
Při uložení a načtení pozice se smažou a znovu vytvoří všechny pixmapy. Tím pádem rovněž přestanou fungovat pointery na ně. Samozřejmě je možné uvědomit modul save o tomto ukazateli pomocí funkce add_sl_var. Některé pixmapy, které jsou načítány na začátku programu a nebudou již mazány, se dají tzv. zafixovat funkcí fix_pix. Tato funkce může být spuštěna pouze jednou, někde před spuštěním hlavního cyklu a zafixuje všechny pixmapy, které již byly načteny. Zafixované pixmapy není možné smazat a nebudou ukládány do souboru. Jejich počet (záporný) funkce fix_pix uloží do proměnné pocet_fixpix a celý seznam přesune z proměnné prvpix do proměnné fixed_pixmaps. Při tom uloží do položky Cislo příslušné záporné pořadí. pixmap.c 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211:
kq_pixmap *fixed_pixmaps = NULL; int pocet_fixpix = 0; void fix_pix () { kq_pixmap *pom; if(pocet_fixpix) warning("funkce fix_pix() je spustitelna jen jednou"); for(pom = prvpix; pom; pom = pom->next) pom->Cislo = --pocet_fixpix; fixed_pixmaps = prvpix; prvpix = NULL; }
15 Modul window Tento modul se stará o správné umístění rámečku s obrázky a s textem v hlavním okně. Sám také řeší pozadí rámečku s obrázky. Okno může mít dva módy, fullscreened a windowed, které se mírně void deleteApixmaps(): 37, 147, 188 kq_pixmap *fixed_pixmaps: 37, 150
void fix_pix(): 37, 74
37
int pocet_fixpix: 37, 136–137, 150
15 Modul window
Program kraluk
liší způsobem počítání rozmístění okna. To, zda je právě hra v módu fullscreened určuje proměnná fullscreened (0 = W, 1 = FS). V módu windowed má rámeček pro vykreslování obrázků přesnou velikost určenou podle velikosti pozadí a poměru zvětšení. Okolo toho se obalí celé okno a výsledný obrázek pak vypadá nějak takto:
Šipečky znázorňují šířku bílého okraje, který je okolo rámečku s textem nebo okolo rámečku s obrázkem. Tato šířka je uložena v proměnné OKRAJ. V módu fullscreened má okno pevně danou velikost. Obrázek pak vypadá takto:
To co předtím tvořilo celý rámeček s obrázkem, teď už tvoří jen oblast, do které by se měl tento rámeček s obrázkem vejít. Program tedy spočítá největší možný poměr zvětšení (ratio) a umístí rámeček s obrázkem doprostřed té oblasti. Rámeček (tedy datový typ Window), do kterého se vykreslují obrázky, je win a rámeček, do kterého se vykresluje text, je textwin. Proměnná win je nastavena na None do vytvoření okna, tedy startu hry. window.c 16: Window win = None; 17: Window textwin = None;
char fullscreened: 11, 39–40, 42–43, 161–162 int OKRAJ: 11, 39–44 Window win: 38–47, 62, 87–88, 113, 117, 119–121, 123, 140, 147, 163, 165–166, 181–182, 186, 188 Window textwin: 23, 38–41, 43, 109–111, 113, 120, 123, 163, 165
38
15 Modul window
Program kraluk
Tyto dvě okna jsou uvnitř hlavního okna real_win a za nimi uvnitř real_win je bílé okno okrajwin, které kolem aktivního win nebo textwin vytváří bílý okraj o šířce OKRAJ. window.c 21: static Window real_win; 22: static Window okrajwin;
Dále si uchovávám všelijaké rozměry v okně. Proměnné real_win_vyska a real_win_sirka udávají rozměry Hlavního okna hry. Proměnné win_x a win_y udávají pozici okna win uvnitř real_win a proměnné win_vyska a win_sirka udávají rozměry okna win. window.c 26: static int real_win_vyska, real_win_sirka, win_x, win_y; window.h 4: int win_vyska, win_sirka;
Šířka textwin je v proměnné text_sirka. To je šířka hlavního okna bez okraje, což se dá spočítat jako real_win_sirka - 2*OKRAJ. Výška textwin je uložena v proměnné text_vyska. Ta však není nastavena v modulu window, ale funkcí loadfont z modulu edit. window.h 2: int text_sirka, text_vyska;
Pozadí win je v proměnné pozadi, která obsahuje podobně jako struktura kq_pixmap pixmapu v položce barvy a ximage v položce ibarvy, přičemž barvy už jsou narozdíl od ibarvy vyscalované. window.h 8: struct { 9: Pixmap barvy; 10: XImage *ibarvy; 11: } pozadi;
Okno se všemi podokny se vytvoří funkcí vytvorokno. Tato funkce musí dostat jako parametr název souboru pro pozadí. window.c 260: void vytvorokno (char *pnazev) 261: /****************************/ 262: { 263: char *fullname; 264: 265: loadfont(); // Nactu font. 266: loadpopupfont(); // Nactu font pro vyskakovaci okna. 267: 268: // Nastavim udaje o oknech: 269: 270: fullname = joinstrings(BGDIR, pnazev, NULL); 271: if(fullscreened){ 272: pozadi.barvy = nactiXPM(fullname, &pozadi.ibarvy, NULL, NULL); 273: if(!ratio) ratio = spoctifr(); // spocitam ratio pro fullscreen 274: if(!unfullratio) unfullratio = ratio; 275: rescalePixmap(pozadi.ibarvy, &pozadi.barvy); 276: 277: win_x = (display_sirka-pozadi.PIX_SIR*ratio)/2; 278: win_y = (display_vyska-OKRAJ-text_vyska-pozadi.PIX_VYS*ratio)/2; 279: win_sirka = pozadi.PIX_SIR*ratio; 280: win_vyska = pozadi.PIX_VYS*ratio; 281: real_win_sirka = display_sirka; 282: real_win_vyska = display_vyska; 283: text_sirka = display_sirka-2*OKRAJ; 284: } 285: else{ 286: pozadi.barvy = nactiXPM(fullname, &pozadi.ibarvy, NULL, NULL); 287: win_x = win_y = OKRAJ; 288: win_sirka = pozadi.PIX_SIR*ratio; 289: win_vyska = pozadi.PIX_VYS*ratio; Window real_win /*window*/ : 39–44 Window okrajwin: 39–42, 161 int real_win_vyska /*window*/ : 39–43 int real_win_sirka /*window*/ : 39–43 int win_x /*window*/ : 39–41, 44 int win_y /*window*/ : 39–41, 44 int win_vyska: 39–41, 43, 120–121, 124, 186 int win_sirka: 39–43, 119–121, 124, 186 int text_sirka: 39–40, 43, 109, 111, 113 int text_vyska: 39–40, 42–43, 109, 111 pozadi: 39–40, 42–43 void vytvorokno(): 39, 147, 172
39
15 Modul window 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: }
Program kraluk
real_win_sirka = win_sirka+2*OKRAJ; real_win_vyska = win_vyska+text_vyska+3*OKRAJ; text_sirka = win_sirka; } free(fullname); // Vytvorim okna: real_win = XCreateSimpleWindow(display, root, 0, 0, real_win_sirka, real_win_vyska, 0, BlackPixel(display,screen), BlackPixel(display,screen)); if(okrajtext){ okrajwin = XCreateSimpleWindow(display, real_win, 0, real_win_vyska - (text_vyska+2*OKRAJ), real_win_sirka, text_vyska+2*OKRAJ, 0, WhitePixel(display,screen), WhitePixel(display,screen)); } else{ okrajwin = XCreateSimpleWindow(display, real_win, win_x-OKRAJ, win_y-OKRAJ, win_sirka+2*OKRAJ, win_vyska+2*OKRAJ, 0, WhitePixel(display,screen), WhitePixel(display,screen)); } win = XCreateSimpleWindow(display, real_win, win_x, win_y, win_sirka, win_vyska, 0, BlackPixel(display,screen), BlackPixel(display,screen));
textwin = XCreateSimpleWindow(display, real_win, OKRAJ, real_win_vyska-text_vyska-OKRAJ, text_sirka, text_vyska, 0, WhitePixel(display,screen), BlackPixel(display,screen)); XSetWindowBackgroundPixmap(display, win, pozadi.barvy); // Nastavim pozadi. // Nastavim prijimani udalosti XSelectInput(display, real_win, KeyPressMask | ButtonPressMask); XSelectInput(display, textwin, ExposureMask); // Vytvorim text_gc: text_gc = XCreateGC(display, textwin, 0, NULL); XSetFont(display, text_gc, font_info->fid); XSetForeground(display, text_gc, WhitePixel(display,screen)); // Placnu okno na obrazovku: XMapWindow(display, XMapWindow(display, XMapWindow(display, XMapWindow(display, XFlush(display);
real_win); okrajwin); textwin); win);
// Nastavim udaje o oknu XSetStandardProperties(display, real_win, WINDOW_NAME, ICON_NAME, None, gargv, gargc, NULL); if(fullscreened){ send_fs_event(); } else fixujokno(); nastavicon();
40
15 Modul window
Program kraluk
Funkce nastavicon by měla nastavit obrázek ikonky. V některých windowmanagerech však zatím není zcela spolehlivá. window.c 30: static void nastavicon () 31: { 32: int orat; 33: XWMHints wmhints; 34: XClassHint classhint; 35: 36: orat = ratio; 37: ratio = 1; 38: wmhints.icon_pixmap = nactiXPM("icon", NULL, &wmhints.icon_mask, NULL); 39: ratio = orat; 40: 41: wmhints.flags = IconPixmapHint|IconMaskHint; 42: wmhints.input = 1; 43: 44: classhint.res_name = gargv[0]; 45: classhint.res_class = ICON_NAME; 46: 47: XSetClassHint(display, real_win, &classhint); 48: XSetWMHints(display, real_win, &wmhints); 49: }
Funkcí fixujokno zařídím, aby nešla měnit velikost okna hry. window.c 85: static void fixujokno () 86: { 87: XSizeHints size_hints; 88: 89: // Nastavim maximalni i minimalni velikost okna jako aktualni velikost: 90: 91: size_hints.flags = PSize | PMinSize | PMaxSize; 92: size_hints.width=size_hints.min_width=size_hints.max_width=real_win_sirka; 93: size_hints.height=size_hints.min_height=size_hints.max_height=real_win_vyska; 94: 95: XSetWMNormalHints(display, real_win, &size_hints); 96: }
Oproti tomu funkce odfixujokno opět možnost měnit velikost okna povolí. window.c 100: static void odfixujokno () 101: { 102: XSizeHints size_hints; 103: 104: size_hints.flags = 0; 105: 106: XSetWMNormalHints(display, real_win, &size_hints); 107: }
Pro nastavení bílého okraje jsou funkce okraj_to_win (dá okrajwin okolo win) a okraj_to_text (dá okrajwin okolo textwin). Navíc tyto funkce nastaví proměnnou okrajtext, která je true, pokud je okraj kolem textu. window.h 3: char okrajtext; window.c 243: void okraj_to_win () 244: { 245: XMoveResizeWindow(display, okrajwin, 246: win_x-OKRAJ, win_y-OKRAJ, win_sirka+2*OKRAJ, win_vyska+2*OKRAJ); 247: okrajtext = 0; 248: mengraf = 1; 249: } 250: void nastavicon /*window*/ (): 40–41 void fixujokno /*window*/ (): 40–41, 43 void okraj_to_win(): 41, 112–113, 117, 163–165 void okraj_to_text(): 42–43, 110, 112–113, 163–165 char okrajtext: 11, 19, 25, 40–43, 109–110, 112, 115–116, 161–165
41
15 Modul window
Program kraluk
251: void okraj_to_text () 252: { 253: XMoveResizeWindow(display, okrajwin, 254: 0, real_win_vyska-2*OKRAJ-text_vyska, real_win_sirka, text_vyska+2*OKRAJ); 255: okrajtext = 1; 256: }
Obrázek na pozadí je možné změnit funkcí zmenokno. Tato funkce dostane název souboru pro pozadí. window.c 361: void zmenokno (char *pnazev) // Zmeni pozadi. 362: { 363: int sirka, vyska; 364: char *fullname; 365: 366: // Ulozim puvodni sirku a vysku: 367: 368: sirka = pozadi.PIX_SIR; 369: vyska = pozadi.PIX_VYS; 370: 371: // Smazu puvodni obrazky: 372: 373: XFreePixmap(display, pozadi.barvy); 374: XDestroyImage(pozadi.ibarvy); 375: 376: fullname = joinstrings(BGDIR, pnazev, NULL); 377: pozadi.barvy = nactiXPM(fullname, &pozadi.ibarvy, NULL, NULL); // Nactu novou pixmapu. 378: free(fullname); 379: 380: XSetWindowBackgroundPixmap(display, win, pozadi.barvy); // Nastavim novou pixmapu. 381: 382: // Vyresim ruznou velikost noveho a stareho pozadi: 383: 384: if(sirka != pozadi.PIX_SIR || vyska != pozadi.PIX_VYS) velikokno(0); 385: 386: // Nakreslim novou pixmapu: 387: 388: XCopyArea(display, pozadi.barvy, win, ggc, 389: 0, 0, 390: sirka*ratio, vyska*ratio, 391: 0, 0); 392: 393: mengraf = 1; 394: }
Pokud má nové pozadí jinou velikost než staré, je třeba správně upravit rozměry. Konkrétně při fullscreenu je třeba spočítat nejvyšší možné ratio, pro které se tam dané pozadí vejde a umístit to doprostřed. Mimo fullscreen je třeba upravit velikost real_win. Tyto operace řeší funkce velikokno. Ta dostane navíc parametr fixratio, který znamená, jestli tato funkce může při fullscreenu měnit ratio. Změna ratio na nejvyšší možné takové, aby se tam win vešlo, není žádoucí, pokud byla funkce velikokno zavolána právě proto, že bylo změněno ratio. window.c 144: static void velikokno (int fixratio) 145: { 146: int pratio; 147: 148: if(fullscreened && !fixratio){ 149: pratio = spoctifr(); 150: if(pratio != ratio){ 151: rescale(pratio); 152: return; 153: } 154: } 155: 156: win_sirka = pozadi.PIX_SIR*ratio; void zmenokno(): 42, 147, 171
void velikokno(): 42
42
15 Modul window 157: 158: 159: 160: 161: 162: }
Program kraluk
win_vyska = pozadi.PIX_VYS*ratio; XResizeWindow(display, win, win_sirka, win_vyska); if(fullscreened) umistiwin(); else real_win_to_win();
Správné ratio pro fullscreen spočítá funkce spoctifr. window.c 68: static int spoctifr () 69: { 70: int pratio; // pokusne ratio 71: 72: // Spocitam maximalni ratio, se kterym se win vejde na obrazovku: 73: 74: pratio = (display_sirka-2*OKRAJ)/pozadi.PIX_SIR; 75: if(pratio > (display_vyska-text_vyska-3*OKRAJ)/pozadi.PIX_VYS) 76: pratio = (display_vyska-text_vyska-3*OKRAJ)/pozadi.PIX_VYS; 77: if(pratio < MINRATIO) pratio = MINRATIO; 78: if(pratio > MAXRATIO) pratio = MAXRATIO; 79: 80: return pratio; 81: }
Funkce fullscreen přepne do fullscreenu, pokud je hra v okně a do okna, pokud je hra ve fullscreenu. window.h 5: char fullscreened; window.c 193: void fullscreen () 194: { 195: int pratio; 196: 197: fullscreened = !fullscreened; 198: 199: odfixujokno(); 200: 201: // zmenim velikost okna 202: 203: if(fullscreened){ 204: real_win_sirka = display_sirka; 205: real_win_vyska = display_vyska; 206: XResizeWindow(display, real_win, real_win_sirka, real_win_vyska); 207: } 208: 209: send_fs_event(); // Poslu fullscreenovaci udalost 210: 211: if(fullscreened){ 212: // Dam textwin dospod obrazovky. 213: text_sirka = real_win_sirka-2*OKRAJ; 214: XMoveResizeWindow(display, textwin, 215: OKRAJ, real_win_vyska-OKRAJ-text_vyska, 216: text_sirka, text_vyska); 217: posuntext(); 218: if(okrajtext) okraj_to_text(); 219: 220: unfullratio = ratio; // Zazalohuji ratio. 221: 222: pratio = spoctifr(); // Spocitam maximalni ratio, se kterym se win vejde na obrazovku 223: 224: if(pratio == ratio) umistiwin(); /* Pokud vyjde stejne jako puvodni zvetseni, 225: jen dam win doprostred */ 226: else rescale(pratio); // jinak prescaluji hru 227: } 228: else{
int spoctifr /*window*/ (): 39, 42–43
void fullscreen(): 20, 39, 43
43
16 Modul widget 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: } 239: }
Program kraluk
// Posunu win zpatky do leveho horniho rohu: win_x = win_y = OKRAJ; XMoveWindow(display, win, win_x, win_y); // Vratim puvodni zvetseni: if(unfullratio == ratio) real_win_to_win(); else rescale(unfullratio);
Při přechodu do fullscreenu je ratio nastaveno na nejvyšší možné takové, aby se win vešlo na obrazovku. Předtím je ale původní ratio zazálohováno do proměnné unfullratio. Při návratu do okna se ratio zpět nastaví na tuto hodnotu. window.h 6: int unfullratio;
16 Modul widget Widget je obrázek na obrazovce, s kterým je možné posunovat a dokonce tento obrázek měnit. Techničtěji řečeno to je struktura kq_widget obsahující okno ve win a jeho údaje: souřadnice a aktuální obrázek. Dále obsahuje souřadnici z, která určuje, který widget je nad kterým, tedy nejblíže divákovi je widget s největší Z-kovou souřadnicí. widget.h 1: struct kq_widget{ 2: kq_pixmap *obr; 3: Window okno; 4: int x,y; 5: float z; 6: 7: char hide; 8: char lokalni; 9: 10: kq_widget *next, *prev; 11: unsigned int Cislo; 12: };
Pomocí položek next a prev mám widgety seřazené v seznamu podle své Z-kové souřadnice. Widget, který má nejvyšší Z-kovou souřadnici, nemá žádný widget před sebou, tedy v položce prev je NULL. Tento widget je uložen v proměnné prvwidget. widget.c 11: kq_widget *prvwidget = NULL;
Položka hide ve struktuře widget udává, zda je widget schovaný. Když je widget schovaný, tak má zničené své okno, ale stále obsahuje všechny informace k tomu, aby mohl své okno obnovit. Schovaný widget je navíc v jiném seznamu, který není uchycen na začátku proměnnou prvwidget, ale je uchycen na konci proměnnou poshidwid, tedy widget poshidwid má NULLovou položku next. widget.c 12: kq_widget *poshidwid = NULL;
Funkce hidewidget schová widget. widget.c 326: void hidewidget (kq_widget *w) 327: { 328: if(w->hide) return; 329: w->hide = 1; 330: 331: if(w->next) w->next->prev = w->prev; 332: if(w->prev) w->prev->next = w->next; 333: if(w == prvwidget) prvwidget = w->next; 334: if(w->obr){ int unfullratio: 11, 39, 43–44, 161–162 kq_widget: 7, 44–51, 63, 65, 132, 136–137, 139–140, 143–146, 148, 150, 167, 234 kq_widget *prvwidget: 44, 46–51, 139–140, 143, 147, 233–234 kq_widget *poshidwid: 44–47, 49–51, 139–140, 143, 147 void hidewidget(): 44, 67
44
16 Modul widget 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: }
Program kraluk
XDestroyWindow(display, w->okno); mengraf = 1; } w->prev = poshidwid; w->next = NULL; if(poshidwid) poshidwid->next = w; poshidwid = w; prestackujn(w);
Funkce unhidewidget znovu zobrazí schovný widget. widget.c 346: void unhidewidget (kq_widget *w) 347: { 348: if(!w->hide) return; 349: w->hide = 0; 350: 351: if(w->next) w->next->prev = w->prev; 352: if(w->prev) w->prev->next = w->next; 353: if(w == poshidwid) poshidwid = w->prev; 354: 355: zobrazwidget(w); 356: }
Pokud zatím není vytvořené win, jsou všechny widgety v seznamu schovaných widgetů. Tyto widgety je pak třeba zobrazit funkcí ukazwidgety. Tato funkce také odschová widgety se záporným hide a je spuštěna při přechodu na jiné políčko. Záporné hide se však neukládá, takže je vhodné funkci ukazwidgety zavolat v tom samém framu jako byl widgetu záporný hide nastaven. Dále je třeba upozornit, že dokud není vytvořen win, jediná funkční operace s widgety je jeho vytvoření (funkce vytvorwidget). widget.c 208: void ukazwidgety () 209: { 210: kq_widget *pom, *pomo; 211: 212: for(pom = poshidwid; pom; pom = pomo){ 213: pomo = pom->prev; 214: 215: if(pom->hide <= 0){ 216: pom->hide = 0; 217: if(pom->next) pom->next->prev = pom->prev; 218: if(pomo) pomo->next = pom->next; 219: if(poshidwid == pom) poshidwid = pomo; 220: 221: zobrazwidget(pom); 222: } 223: } 224: }
Funkce vytvorwidget založí nový widget. widget.c 180: kq_widget *vytvorwidget (int x, int y, float z, kq_pixmap *obrazek, 181: char lokalni, char hide) 182: { 183: kq_widget *vysledek; 184: 185: vysledek = (kq_widget *)mymalloc(sizeof(kq_widget)); 186: 187: // Dosadim zadane parametry: 188: 189: vysledek->x = x; 190: vysledek->y = y; 191: vysledek->z = z; 192: vysledek->obr = obrazek; void unhidewidget(): 45, 67 void ukazwidgety(): 45, 171–172 68, 167, 179, 203, 205, 224, 228, 232, 234, 237–238
45
kq_widget *vytvorwidget(): 45,
16 Modul widget 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: }
Program kraluk
vysledek->lokalni = lokalni; vysledek->hide = hide; if(hide){ vysledek->prev = poshidwid; vysledek->next = NULL; if(poshidwid) poshidwid->next = vysledek; poshidwid = vysledek; prestackujn(vysledek); } else zobrazwidget(vysledek); return vysledek;
Po založení struktury je třeba umístit tento widget na správné místo v seznamu a vytvořit jeho okno. To dělá funkce zobrazwidget. widget.c 78: static void zobrazwidget (kq_widget *w) 79: { 80: if(!win){ 81: w->prev = poshidwid; 82: w->next = NULL; 83: if(poshidwid) poshidwid->next = w; 84: poshidwid = w; 85: prestackujn(w); 86: 87: return; 88: } 89: 90: if(w->obr){ 91: 92: // Je-li treba, prescaluji pixmapu: 93: 94: if(w->obr->scaled != ratio){ 95: rescalePixmap(w->obr->ibarvy, &w->obr->barvy); 96: rescalePixmap(w->obr->ikanal, &w->obr->akanal); 97: w->obr->scaled = ratio; 98: } 99: 100: // Vytvorim okno: 101: 102: w->okno = XCreateSimpleWindow(display, win, w->x*ratio, w->y*ratio, 103: w->obr->PIX_SIR*ratio, 104: w->obr->PIX_VYS*ratio, 0, 105: BlackPixel(display,screen), 106: WhitePixel(display,screen)); 107: 108: XShapeCombineMask (display, w->okno, ShapeBounding, 109: 0, 0, w->obr->akanal, ShapeSet); 110: 111: XSetWindowBackgroundPixmap(display, w->okno, w->obr->barvy); 112: 113: mengraf = 1; 114: } 115: 116: // Zaradim widget mezi ostatni widgety: 117: 118: w->next = prvwidget; 119: w->prev = NULL; 120: if(prvwidget) prvwidget->prev = w; 121: prvwidget = w; 122: prestackujd(w); 123: 124: if(w->obr) XMapWindow(display, w->okno); // Zobrazim ho 125: } void zobrazwidget /*widget*/ (): 45–46, 48
46
16 Modul widget
Program kraluk
Pro zařazení widgetu na správné místo v seznamu jsou funkce prestackujd a prestackujn. První funkce posouvá widget v parametru dál od hráče a druhá blíž k hráči. widget.c 68: 69: 70: 71: 72: 73: 74: 75: 76:
static void prestackujd (kq_widget *w) // Posune widget v seznamu doprava { while(w->next && w->next->z > w->z) prohodwid(w); } static void prestackujn (kq_widget *w) // Posune widget v seznamu doleva { while(w->prev && w->prev->z < w->z) prohodwid(w->prev); }
Obě předchozí funkce se opírají o funkci prohodwid. Tato funkce prohodí widget, co dostane v parametru, s tím za ním (v položce next). Přitom, pokud to je možné, prohodí i pořadí oken widgetů. widget.c 14: static void prohodwid (kq_widget *wid1) 15: // Prohodi wid1 s dalsim widgetem. 16: { 17: kq_widget *pom1, *pom2, *wid2; 18: 19: // Dosadim pomocne promenne: 20: 21: wid2 = wid1->next; 22: if(!wid2){ 23: printf("nemuzu prohodit posledni widget\n"); 24: return; 25: } 26: pom1 = wid1->prev; 27: pom2 = wid2->next; 28: 29: /* 30: Nyni mam takoveto widgety: pom1 -> wid1 -> wid2 -> pom2, 31: pricemz cil je je usporadat takto: pom1 -> wid2 -> wid1 -> pom2. 32: */ 33: 34: // Vyresim kraje: 35: 36: if(wid1==prvwidget) prvwidget = wid2; 37: if(wid2==poshidwid) poshidwid = wid1; 38: 39: // Spojim pom1 a wid2: 40: 41: if(pom1) pom1->next = wid2; 42: wid2->prev = pom1; 43: 44: // Spojim pom2 a wid1: 45: 46: if(pom2) pom2->prev = wid1; 47: wid1->next = pom2; 48: 49: // Spojim wid1 a wid2 ze spravne strany: 50: 51: wid2->next = wid1; 52: wid1->prev = wid2; 53: 54: // Nyni mam widgety ve spravnem poradi a jeste je prohodim graficky: 55: 56: if(wid1->hide || !wid1->obr || !wid2->obr || !win) 57: return; 58: 59: Window wpole[2]; 60: 61: wpole[0] = wid2->okno; 62: wpole[1] = wid1->okno; void prestackujd /*widget*/ (): 46–48 void prohodwid /*widget*/ (): 47
void prestackujn /*widget*/ (): 45–48, 50
47
16 Modul widget
Program kraluk
63: XRestackWindows(display, wpole, 2); 64: 65: mengraf = 1; 66: }
Funkce posunzwidghet změní Z-kovou souřadnici. widget.c 289: void posunzwidget (kq_widget *w, float z) 290: { 291: if(w->z == z) return; 292: 293: if(w->z > z){ 294: w->z = z; 295: prestackujd(w); 296: } 297: else if(w->z < z){ 298: w->z = z; 299: prestackujn(w); 300: } 301: }
Funkce posunwidget změní souřadnice x, y widgetu. widget.c 226: void posunwidget (kq_widget *w, int x, int y) 227: { 228: if(w->x != x || w->y != y){ 229: w->x = x; 230: w->y = y; 231: if(w->hide || !w->obr) return; 232: XMoveWindow(display, w->okno, x*ratio,y*ratio); 233: mengraf = 1; 234: } 235: }
Funkce prebarviwidget změní pixmapu přiřazenou widgetu. Tato pixmapa může být také NULL. Pak widget není vidět, ale je v seznamu zobrazených widgetů, tedy za prvwidget. Pokud je položka scaled u nové pixmapy jiná než aktuální ratio, je pixmapa přescalována. widget.c 237: void prebarviwidget (kq_widget *w, kq_pixmap *obrazek) 238: { 239: if(w->obr == obrazek) return; 240: if(w->hide){ 241: w->obr = obrazek; 242: return; 243: } 244: if(obrazek == NULL){ 245: XDestroyWindow(display, w->okno); 246: mengraf = 1; 247: w->obr = NULL; 248: return; 249: } 250: if(w->obr == NULL){ 251: w->obr = obrazek; 252: if(w->prev) w->prev->next = w->next; 253: if(w->next) w->next->prev = w->prev; 254: if(prvwidget == w) prvwidget = w->next; 255: zobrazwidget(w); 256: return; 257: } 258: 259: // Je-li treba, prescaluji pixmapu: 260: 261: if(obrazek->scaled != ratio){ 262: rescalePixmap(obrazek->ibarvy, &obrazek->barvy); 263: rescalePixmap(obrazek->ikanal, &obrazek->akanal);
void posunzwidghet
void posunwidget: 48, 234, 238–239
48
void prebarviwidget(): 48, 67, 167
16 Modul widget 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: }
Program kraluk
obrazek->scaled = ratio; } // Zmenim velikost okna pro novou pixmapu: if(w->obr->PIX_VYS != obrazek->PIX_VYS || w->obr->PIX_SIR != obrazek->PIX_SIR) XResizeWindow(display, w->okno, obrazek->PIX_SIR*ratio, obrazek->PIX_VYS*ratio); // Nastavim pixmapu: w->obr = obrazek; XSetWindowBackgroundPixmap(display, w->okno, obrazek->barvy); XShapeCombineMask (display, w->okno, ShapeBounding, 0, 0, obrazek->akanal, ShapeSet); XCopyArea(display, obrazek->barvy, w->okno, ggc, 0, 0, obrazek->PIX_SIR*ratio, obrazek->PIX_VYS*ratio, 0, 0); mengraf = 1;
Funkce znicwidget smaže widget. widget.c 310: void znicwidget (kq_widget *w) 311: { 312: if(w->next) w->next->prev = w->prev; 313: else if(w->hide) poshidwid = w->prev; 314: 315: if(w->prev) w->prev->next = w->next; 316: else if(!w->hide) prvwidget = w->next; 317: 318: if(!w->hide && w->obr){ 319: XDestroyWindow(display, w->okno); 320: mengraf = 1; 321: } 322: 323: free(w); 324: }
Funkce deletelwidgets smaže všechny widgety, které mají položku lokalni kladnou, a widgety, které mají položku lokalni zápornou, schová. Nezměněné tedy zůstanou jen widgety, které měly položku lokalni nulovou. Tato funkce je spuštena při odchodu z políčka. widget.c 358: void deletelwidgets () 359: { 360: /* 361: Promennou pomo vzdy naleznu nejblizsi nelokalni widget, pricemz 362: mazu widgety za ni. Pak to propojim s predchozim nelokalnim widgetem 363: pomoci pom. 364: */ 365: 366: kq_widget **pom; 367: kq_widget *pomo; 368: kq_widget *pomoc; 369: 370: for(pom = &poshidwid;;){ 371: for(pomo = *pom; pomo && pomo->lokalni > 0; pomo = pomoc){ 372: pomoc = pomo->prev; 373: free(pomo); 374: } 375:
void znicwidget(): 49, 68, 212, 233–234, 239
void deletelwidgets(): 49, 173
49
16 Modul widget 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: }
Program kraluk
if(!pomo) break; pomo->next = (*pom)->next; *pom = pomo; pom = &(pomo->prev); } *pom = NULL; for(pom = &prvwidget;; pom = &(pomo->next)){ for(pomo = *pom; pomo && pomo->lokalni; pomo = pomoc){ pomoc = pomo->next; if(pomo->obr) XDestroyWindow(display, pomo->okno); mengraf = 1; if(pomo->lokalni > 0) free(pomo); else{ pomo->hide = 1; pomo->prev = poshidwid; pomo->next = NULL; if(poshidwid) poshidwid->next = pomo; poshidwid = pomo; prestackujn(pomo); } } if(!pomo) break; pomo->prev = (*pom)->prev; *pom = pomo; } *pom = NULL;
Funkce deleteAwidgets smaže všechny widgety. Je použita při restartu nebo při načtení pozice. widget.c 409: void deleteAwidgets () 410: { 411: kq_widget *pom; 412: 413: while(prvwidget){ 414: pom = prvwidget->next; 415: if(prvwidget->obr) XDestroyWindow(display, prvwidget->okno); 416: free(prvwidget); 417: prvwidget = pom; 418: } 419: while(poshidwid){ 420: pom = poshidwid->prev; 421: free(poshidwid); 422: poshidwid = pom; 423: } 424: }
Pro ladění tu jsou k dispozici funkce vypiswidget a vypiswidgety. První funkce vypíše parametry widgetu, který dostane v parametru. Druhá pomocí té první vypíše všechny widgety. widget.c 426: void vypiswidget (kq_widget *w) 427: { 428: if(w == NULL){ 429: printf("NULL\n"); 430: return; 431: } 432: 433: if(w->lokalni == 0) printf("global "); 434: if(w->lokalni > 0) printf("local "); 435:
void deleteAwidgets(): 50, 147, 188
void vypiswidget(): 50–51
50
void vypiswidgety(): 51
17 Modul filer 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459:
Program kraluk
printf("widget, obr="); if(w->obr == NULL) printf("NULL"); else printf("\"%s\"", w->obr->nazev); printf(", x=%d, y=%d, z=%f", w->x,w->y,w->z); if(w->hide) printf("\tHIDEN"); printf("\n"); } void vypiswidgety () { kq_widget *pom; printf("schovane widgety:\n"); for(pom=poshidwid; pom; pom = pom->prev){ printf(" "); vypiswidget(pom); } printf("zobrazene widgety:\n"); for(pom=prvwidget; pom; pom = pom->next){ printf(" "); vypiswidget(pom); } printf("\n"); }
17 Modul filer Tento modul tu je kvůli načítání XPM souborů do struktury kq_map. Je nadstavbou nad standardním datovým typem FILE a funkcemi fopen, fgetc a fclose. Funkce mf_otevri otevře soubor ke čtení a v parametru vrátí ukazatel na kq_filer. filer.c 7: kq_filer *mf_otevri (char *nazev) 8: { 9: kq_filer *vysledek; 10: vysledek = (kq_filer *)mymalloc(sizeof(kq_filer)); 11: if((vysledek->file = fopen (nazev, "r")) == NULL) 12: error ("mf_otevri(\"%s\")", nazev); 13: 14: vysledek->nazev = nazev; 15: vysledek->x = 0; 16: vysledek->y = 1; 17: vysledek->ch = EOF; 18: 19: return vysledek; 20: }
Struktura kq_filer vypadá následovně filer.h 1: struct kq_filer{ 2: char *nazev; 3: int ch, x, y; 4: FILE* file; 5: };
Položky x a y udávají souřadnice znaku, co se bude právě číst. Na začátku jsem na prvním řádku a sloupci 0. V položce nazev si uchovávám plnou cestu ke čtenému souboru. V položce ch je přečtený, ale nevyužitý znak, který bude použit, jakmile bude použita funkce, která čte ze souboru. Pokud žádný nevyužitý znak není, je v položce ch hodnota EOF. Základní funkcí pro čtení ze souboru je funkce mf_znak, která vrátí přečtený znak.
kq_filer *mf_otevri: 51, 54
kq_filer: 7, 51–54
51
int mf_znak(): 52, 55
17 Modul filer
Program kraluk filer.c
34: int mf_znak (kq_filer *soubor) 35: { 36: int ch; 37: 38: if(soubor->ch != EOF){ 39: ch=soubor->ch; 40: soubor->ch = EOF; 41: } 42: else{ 43: ch = fgetc(soubor->file); 44: 45: if(ch==’\n’){ 46: soubor->y++; 47: soubor->x=0; 48: } 49: else soubor->x++; 50: } 51: return ch; 52: }
Funkce mf_najdi přečte (přeskočí) soubor až po první výskyt zadaného znaku. Při dalším čtení souboru je pokračováno za tímto znakem. filer.c 54: void mf_najdi (kq_filer *soubor, char znak) 55: { 56: int ch; 57: 58: while((ch = mf_znak(soubor)) != znak) 59: if(ch == EOF){ 60: warning("mf_najdi(’%c’)", znak); 61: mf_error(soubor); 62: } 63: }
Funkce mf_musibyt dostane string, který se musí vyskytovat v místě aktuálního čtení. V případě, že tam tento string není, program skončí chybou. Po skončení funkce mf_musibyt je zadaný string už považován za přečtený. filer.c 65: void mf_musibyt (kq_filer *soubor, char *retezec) 66: { 67: int i; 68: for(i=0; retezec[i] != 0; i++) 69: if(mf_znak(soubor) != retezec[i]){ 70: warning ("mf_musibyt(%s)", retezec); 71: mf_error(soubor); 72: } 73: }
Funkce mf_cislo přečte ze souboru celé nezáporné číslo v desítkové soustavě. Tato funkce konečně využívá položku ch ve struktuře kq_filer. Musí totiž přečíst znak za číslem, aby zjistila, že číslo skončilo, ale nechce, aby tento znak byl považován za přečtený. filer.c 75: int mf_cislo (kq_filer *soubor) 76: { 77: int vysledek, ch; 78: 79: vysledek = mf_znak(soubor)-’0’; 80: if(vysledek < 0 || vysledek > 9){ 81: warning ("mf_cislo()"); 82: mf_error(soubor); 83: } 84: 85: while((ch=mf_znak(soubor)) >= ’0’ && ch <= ’9’) 86: vysledek = 10*vysledek+ch-’0’; 87: soubor->ch = ch; void mf_najdi(): 52, 54–55
void mf_musibyt(): 52, 54–55
52
int mf_cislo(): 52, 54–55
18 Modul color
Program kraluk
88: 89: return vysledek; 90: }
Pokud cokoliv selže, spustí se funkce mf_error, která vypíše informace o souboru a ukončí program. filer.c 28: void mf_error (kq_filer *soubor) 29: { 30: error("soubor:\"%s\", %d. radek, %d. znak", 31: soubor->nazev, soubor->y, soubor->x); 32: }
Nakonec se soubor zavře funkcí mf_zavri. filer.c 22: void mf_zavri (kq_filer *soubor) 23: { 24: fclose(soubor->file); 25: free(soubor); 26: }
18 Modul color Podívejte se na XPM obrázky v adresáři kraluk-data/images/maps. Jsou to mapy, které pomocí smluvených barev vyjadřují, jaké aktivity na určitém místě scény mohou podnikat jednotlivé postavy (neprojde zdí, utopí se v řece atd.). Kdykoli v této dokumentaci mluvím o barvě, myslím tyto smluvené barvy, nikoli barvy obrázků, které vidí hráč, když hraje hru. Tento modul definuje strukturu kq_color. Do barev by nemělo být zasahováno v průběhu hry, protože nejsou ukládány do souboru, kam ukládám pozici. color.h 3: struct kq_color{ 4: char znak; 5: char *nazev; 6: char zed; 7: float z; 8: kq_color *next; 9: void (*odchfunc)(kq_postava *post, kq_color *obarva, kq_color *nbarva); 10: void (*prichfunc)(kq_postava *post, kq_color *nbarva, kq_color *obarva); 11: };
Položka nazev je string, pod kterým je barva zanesena v XPM souboru. Bývá to kříž a pak hexakód barvy, například "#00FF00" je zelená. Do položky znak se pak při načítání mapy zkopíruje znak, pod kterým je barva v XPM souboru používána. Položka z se sčítá se Z-kovou souřadnicí struktury kq_submap. Položka zed určuje, zda na ní panáček může nebo nemůže vstoupit (true = nemůže). Položka odchfunc je funkce, která se spustí při odchodu panáčka z barvy a dostane parametry: postava, která odešla z barvy, barva, ze které bylo odejito, barva, do které bylo přijito. Položka prichfunc je funkce, která se spustí při vstupu do barvy a dostane parametry: postava, která odešla z barvy, barva, do které bylo přijito, barva, ze které bylo odejito. Každá z těchto funkcí tedy dostane dříve tu barvu, které se týká. Při posunu panáčka je spuštěna funkce spustfb, která spustí příslušné funkce. Dostane stejné parametry, jako by dostala funkce prichfunc. Nejprve je spuštěna odchfunc a pak teprve prichfunc. color.c 28: void spustfb (struct kq_postava *post, kq_color *nbarva, kq_color *obarva) 29: { 30: if(obarva == nbarva) return; 31: 32: if(obarva->odchfunc && !(nbarva->zed && post->zdi)) 33: obarva->odchfunc(post, obarva, nbarva); 34: if(nbarva->prichfunc) nbarva->prichfunc(post, nbarva, obarva); void mf_error(): 52–53, 55 void mf_zavri(): 53, 55 kq_color: 7, 53–56, 60–61, 69, 137, 168, 173, 185, 192, 196, 217–225 void spustfb(): 53, 63, 68–69, 174
53
19 Modul map
Program kraluk
35: }
Barvy jsou pomocí položky next zásobníkově členěny do seznamu začínajícího položkou prvbarva. Přidání barvy do seznamu provede funkce pridejbarvu. Ta dostane název této barvy a údaj, zda se jedná o zeď. color.c 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26:
kq_color *prvbarva = NULL; kq_color *pridejbarvu (char *nazev, char zed) /**********************************************/ { kq_color *pom; pom = prvbarva; prvbarva = (kq_color *)mymalloc(sizeof(kq_color)); prvbarva->nazev = nazev; prvbarva->zed = zed; prvbarva->z = 0; prvbarva->next = pom; prvbarva->odchfunc = NULL; prvbarva->prichfunc = NULL; return prvbarva; }
19 Modul map Tento modul úzce souvisí s modulem color. Zakládá datový typ kq_map. Je to dvourozměrné pole ukazatelů na barvu, které obsahuje zároveň informaci o svých rozměrech (položky sirka a vyska). Ve skutečnosti je pole uloženo jako jednorozměrné kvůli usnadnění práce s pamětí. Jednotlivé barvy jsou do tohoto pole do položky pole ukládány po řádcích. Struktura kq_map bývá používána přímo, tedy ne jako ukazatel. Ze souřadnic vrátí příslušnou barvu funkce mappixel. map.c 303: kq_color *mappixel (kq_map map, int x, int y) 304: { 305: if(!map.pole) return NULL; 306: if(x < 0 || y < 0 || x >= map.sirka || y >= map.vyska) return NULL; 307: return map.pole[x+y*map.sirka]; 308: }
Struktura kq_map je založena z XPM souboru funkcí nactimapu. Tato funkce při čtení souboru nejprve do nalezených barev přiřadí příslušný znak a potom hledá, která barva onen znak má. map.c 23: kq_map nactimapu (char *filename) 24: { 25: kq_filer *soubor; 26: int znak, ch, i, j, k, pocetbarev; 27: kq_color *pom, *pomo; 28: kq_map vysledek; 29: char *fullname; 30: 31: for(pom = prvbarva; pom != NULL; pom = pom->next) pom->znak = 0; // pronuluji znaky barev 32: 33: fullname = joinstrings(DATADIR, MAPDIR, filename, MAPSUFFIX, NULL); 34: 35: soubor = mf_otevri(fullname); 36: mf_musibyt(soubor, "/* XPM */"); 37: mf_najdi(soubor, ’"’); 38: 39: vysledek.sirka = mf_cislo(soubor); 40: mf_musibyt(soubor, " "); kq_color *prvbarva: 54–55, 137, 168–171, 188 kq_color *pridejbarvu(): 54, 168, 192, 194, 196, 199–200, 217 kq_map: 7, 51, 54, 56 kq_color *mappixel(): 54, 60, 69, 77, 173–174, 218–219, 230–232, 239–240 kq_map nactimapu(): 54, 57, 148
54
19 Modul map 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: }
Program kraluk
vysledek.vyska = mf_cislo(soubor); mf_musibyt(soubor, " "); pocetbarev = mf_cislo(soubor); mf_musibyt(soubor, " 1\""); // nacitam znaky barev: for(i=0; i<pocetbarev; i++){ mf_najdi(soubor, ’"’); znak=mf_znak(soubor); mf_musibyt(soubor, "
c ");
ch=1; pom = prvbarva; for(j=0; ch; j++){ ch = mf_znak(soubor); if(ch == EOF){ warning ("Konec souboru pri nacitani %d. barvy", j); mf_error(soubor); } if(ch == ’"’){ ch=0; soubor->ch = ’"’; } k=j; for(pomo = pom; pom; pom = pom->next){ while(k < j && pom->nazev[k] == pomo->nazev[k]) k++; if(k==j && pom->nazev[k] == ch) break; k=0; } if(pom == NULL) break; } if(pom != NULL) pom->znak = znak; mf_najdi(soubor, ’"’); } vysledek.pole = allocpole(vysledek.sirka, vysledek.vyska); // nacitam pole: for(i=0; i
next) if(znak && znak == pom->znak){ vysledek.pole[j + i*vysledek.sirka] = pom; break; } if(pom == NULL){ warning ("Neznama barva: %d=’%c’", znak, znak); mf_error(soubor); } } mf_musibyt(soubor, "\""); } mf_zavri(soubor); free(fullname); return vysledek;
Pro alokaci správně velkého pole používám funkci allocpole. Původně bylo pole barev skutečně dvourozměrné, takže byla tato funkce složitější. Nyní jen zavolá malloc. map.c 18: static kq_color **allocpole (int sirka, int vyska) 19: {
55
19 Modul map
Program kraluk
20: return (kq_color **)mymalloc(sizeof(kq_color **)*sirka*vyska); 21: }
19.1
submap
Ve hře je hlavní mapa uložená v proměnné mapa. Tato mapa však není generována ze souboru, ale z ostatních načtených map. map.h 6: kq_map mapa;
Ostatní mapy mají ještě údaj o souřadnicích, kde se na hlavní mapě vyskytují. Takovým mapám říkám submapy a jsou datovým typem kq_submap. map.h 11: struct kq_submap{ 12: int x, y; 13: float z; 14: kq_map map; 15: char hide; 16: char lokalni; 17: kq_submap *next; 18: char *nazev; 19: int Cislo; 20: };
Položky x, y, z určují souřadnice submapy. X-ová souřadnice udává, o kolik políček je submapa posunuta doprava a Y-ová souřadnice udává, o kolik políček je submapa posunuta dolů. Z-ková souřadnice funguje podobně jako u widgetů, tedy čím má submapa vyšší Z-kovou souřadnici, tím je blíž, tedy tím spíš se promítne do hlavní mapy. U map je však Z-ková souřadnice sčítána se Z-kovou souřadnicí barvy. Příklad: Bílá má Z-kovou souřadnici 0 a černá a žlutá má Z-kovou souřadnici 2. Mám celou černou submapu se Z-kovou souřadnicí 0. Nad ní je submapa jejíž z=1 a obsahuje bílou a žlutou barvu. Do hlavní mapy se tak promítne to, co bylo v druhé submapě žluté, zbytek je černý. Pro efektivnější práci se Z-kovými souřadnicemi submap a barev mám pole mapa_z, které není součástí jiné struktury, ale patří k hlavní mapě. Toto pole však není polem barev, ale Z-kových souřadnic. Pro každé políčko v mapě tedy obsahuje informaci, jakou Z-kovou souřadnici má příslušné políčko, tedy součet Z-kových souřadnic barvy a submapy. Kromě toho funguje mapa_z jako ukazatel, zda existuje mapa, pokud mapa není, tak mapa_z = NULL. map.c 12: float *mapa_z = NULL;
Specifickou submapou je bg_map, se kterou nefungují operace s běžnými submapami a určuje samotnou mapu. Tedy je na souřadnicích 0, 0, 0 a podle jejích rozměrů jsou určeny i rozměry hlavní mapy. map.c 14: kq_submap *bgmap = NULL;
Pro změnu bgmap je připravena funkce zmenbgmap. Tato funkce dostane název souboru, ze kterého má přečíst novou submapu. Pokud je tento název NULL, je bgmap, tedy i mapa, zrušena. map.c 210: void zmenbgmap (char *filename) 211: { 212: if(bgmap){ 213: free(bgmap->map.pole); 214: free(bgmap->nazev); 215: } 216: 217: if(!filename){ 218: if(bgmap){ 219: vyradsubmap(bgmap, &prvsubmap); 220: free(bgmap); 221: bgmap = NULL; 222: } 223: return; kq_map mapa: 35–36, 56, 58–60, 62–63, 69–70, 77, 141, 152, 168–174, 179, 203, 218–219, 230–232, 239–240 kq_submap: 7, 53, 56–63, 65, 132, 136–137, 139–140, 143, 145–146, 148, 151, 174–175 float *mapa_z: 56, 58–60, 62, 69–70, 77, 173–174 kq_submap bg_map void zmenbgmap(): 56, 171–172
56
19 Modul map 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: }
Program kraluk
} if(!bgmap){ bgmap = (kq_submap *)mymalloc(sizeof(kq_submap)); bgmap->x = 0; bgmap->y = 0; bgmap->z = 0; bgmap->hide = 0; bgmap->lokalni = 0; zaradsubmap(bgmap, &prvsubmap); } bgmap->map = nactimapu(filename); bgmap->nazev = dupstr(filename); if(autoreloadmap) reloadmap();
Funkce vytvorsubmap založí jinou submapu než bgmap. Předá submapě své parametry a vrátí její ukazatel. map.c 241: kq_submap *vytvorsubmap (int x, int y, float z, char *filename, 242: char lokalni, char hide) 243: { 244: kq_submap *vysledek; 245: 246: vysledek = (kq_submap *)mymalloc(sizeof(kq_submap));; 247: vysledek->x = x; 248: vysledek->y = y; 249: vysledek->z = z; 250: vysledek->hide = hide; 251: vysledek->lokalni = lokalni; 252: vysledek->map = nactimapu(filename); 253: vysledek->nazev = dupstr(filename); 254: 255: if(hide) zaradsubmap(vysledek, &prvhidsm); 256: else{ 257: zaradsubmap(vysledek, &prvsubmap); 258: if(autoreloadmap) pouzijsubmap(vysledek); 259: } 260: 261: return vysledek; 262: }
Funkce znicsubmap submapu odstraní a uvolní z paměti. map.c 367: void znicsubmap (kq_submap *sm) 368: { 369: if(sm == bgmap){ 370: warning("znicsubmap(bgmap)"); 371: return; 372: } 373: 374: if(sm->hide) vyradsubmap(sm, &prvhidsm); 375: else{ 376: vyradsubmap(sm, &prvsubmap); 377: if(autoreloadmap) zrussubmap(sm); 378: } 379: 380: freesm(sm); 381: }
Tato funkce využívá funkci freesm, která submapu jen uvolní z paměti. map.c 360: static void freesm (kq_submap *sm) 361: { 362: free(sm->map.pole); kq_submap *vytvorsubmap(): 57, 64, 175, 205, 208, 222, 232, 234, 237–238 68, 207, 222 void freesm /*map*/ (): 57, 62
57
void znicsubmap(): 57, 64,
19 Modul map
Program kraluk
363: free(sm->nazev); 364: free(sm); 365: }
Submapy jsou položkou next řazeny do seznamu začínajícího submapou prvsubmap. map.h 22: kq_submap *prvsubmap, *bgmap, *prvhidsm;
Stejně jako v případě widgetů je prvsubmap submapa s nejvyšší Z-kovou souřadnicí. Dále jsou submapy seřazeny sestupně podle této souřadnice. Funkce zaradsubmap zařadí submapu do správného místa seznamu. Ukazatel na seznam, do kterého má submapu zařadit je předán v parametru. map.c 191: static void zaradsubmap (kq_submap *sm, kq_submap **prvni) 192: { 193: while(*prvni && (*prvni)->z > sm->z) prvni = &(*prvni)->next; 194: 195: sm->next = *prvni; 196: *prvni = sm; 197: }
Funkce vyradsubmap vyřadí submapu ze seznamu. Ukazatel na seznam je jí předán v parametru stejně jako u funkce zaradsubmap. map.c 199: static void vyradsubmap (kq_submap *sm, kq_submap **prvni) 200: { 201: while(*prvni && *prvni != sm) prvni = &(*prvni)->next; 202: if(!*prvni){ 203: warning("submapa nenalezena"); 204: return; 205: } 206: 207: *prvni = sm->next; 208: }
Promítání submap do mapy ovšem není tak jednoduché, jak to zatím vypadá. Okamžitá úprava hlavní mapy je provedena pouze v případě, že je proměnná autoreloadmap nastavena na true. Po nastavení této hodnoty na true je vhodné spustit funkci reloadmap, která přepočítá celou hlavní mapu. Udělá to tak, že nejprve do hlavní mapy zkopíruje bgmap a potom prochází ostatní submapy a promítne je do hlavní mapy funkcí pouzijsubmap. Není však vhodné nechávat v mapě něco jiného, než v ní má být, protože se mapa neukládá do souboru. map.c 16: char autoreloadmap = 0; map.c 264: void reloadmap () 265: { 266: int i; 267: kq_submap *pom; 268: 269: if(!bgmap){ 270: if(mapa_z){ 271: free(mapa_z); 272: free(mapa.pole); 273: } 274: mapa.pole = NULL; 275: mapa_z = NULL; 276: return; 277: } 278: 279: if(!mapa_z || 280: mapa.sirka != bgmap->map.sirka || 281: mapa.vyska != bgmap->map.vyska){ 282: 283: if(mapa_z){ kq_submap *prvsubmap: 56–62, 139–140, 143, 147–148, 222, 234 void zaradsubmap /*map*/ (): 57–58, 61 void vyradsubmap /*map*/ (): 56–58, 61 char autoreloadmap: 57–58, 61–62, 147, 171–173, 188 void reloadmap(): 57–58, 62, 148, 171–172, 187, 234
58
19 Modul map 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: }
Program kraluk
free(mapa_z); free(mapa.pole); } mapa.sirka = bgmap->map.sirka; mapa.vyska = bgmap->map.vyska; mapa.pole = allocpole(mapa.sirka, mapa.vyska); mapa_z = (float *)mymalloc(sizeof(float *)*mapa.sirka*mapa.vyska); } for(i=0; i<mapa.sirka*mapa.vyska; i++){ mapa.pole[i] = bgmap->map.pole[i]; mapa_z[i] = bgmap->map.pole[i]->z; } for(pom = prvsubmap; pom; pom = pom->next) if(pom != bgmap) pouzijsubmap(pom);
Funkce pouzijmapu dostane submapu, kterou zkopíruje do správné části hlavní mapy. Ovšem pouze tam, kde je součet Z-kové souřadnice submapy a barvy vyšší než příslušné políčko v mapa_z. map.c 122: static void pouzijsubmap (kq_submap *sm) 123: { 124: int x, y, sx, sy; 125: 126: if(!mapa_z) return; 127: 128: if(sm->x < 0){ 129: x = 0; 130: sx = -sm->x; 131: } 132: else{ 133: x = sm->x; 134: sx = 0; 135: } 136: for(; sx < sm->map.sirka && x < mapa.sirka; x++, sx++){ 137: if(sm->y < 0){ 138: y = 0; 139: sy = -sm->y*sm->map.sirka; 140: } 141: else{ 142: y = sm->y*mapa.sirka; 143: sy = 0; 144: } 145: for(; sy < sm->map.vyska*sm->map.sirka && y < mapa.vyska*mapa.sirka; 146: y += mapa.sirka, sy += sm->map.sirka){ 147: if(sm->z + sm->map.pole[sx + sy]->z >= mapa_z[x + y]){ 148: mapa_z[x + y] = sm->z + sm->map.pole[sx + sy]->z; 149: mapa.pole[x + y] = sm->map.pole[sx + sy]; 150: } 151: } 152: } 153: }
Tato funce používá čtyři lokální proměnné: x, y, sx, sy. Tyto proměnné jsou synchronisovány tak, aby mapa.pole[x+y] ukazovalo na stejné políčko jako sm->map.pole[sx+sy]. Y-ová souřadnice je vždy násobkem šířky mapy a X-ová je menší než šířka mapy. Podobně funguje funkce zrussubmap, která v místech hlavní mapy, která se shodují s příslušným políčkem přidané submapy, vyhledá v seznamu submap vhodnou náhradu. map.c 155: static void zrussubmap (kq_submap *sm) 156: { 157: int x, y, sx, sy; 158: kq_submap *pom; void pouzijmapu /*map*/ ()
void zrussubmap /*map*/ (): 57, 59–61
59
19 Modul map 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: }
Program kraluk
if(!mapa_z) return; if(sm->x < 0){ x = 0; sx = -sm->x; } else{ x = sm->x; sx = 0; } for(; sx < sm->map.sirka && x < mapa.sirka; x++, sx++){ if(sm->y < 0){ y = 0; sy = -sm->y*sm->map.sirka; } else{ y = sm->y*mapa.sirka; sy = 0; } for(; sy < sm->map.vyska*sm->map.sirka && y < mapa.vyska*mapa.sirka; y += mapa.sirka, sy += sm->map.sirka){ if(mapa_z[x + y] == sm->map.pole[sx + sy]->z + sm->z && mapa.pole[x + y] == sm->map.pole[sx + sy]){ pom = nejvyssipix(x, y/mapa.sirka); mapa.pole[x + y] = smpixel(pom, x, y/mapa.sirka); mapa_z[x + y] = mapa.pole[x + y]->z + pom->z; } } }
Funkce nejvyssipix najde submapu, která má na daných souřadnicích políčko s největší Z-kovou souřadicí. Tuto funkci využívá i funkce zrussubmap, takže je třeba nejprve submapu vyřadit ze seznamu a pak teprve ji zrušit. map.c 104: kq_submap *nejvyssipix (int x, int y) 105: { 106: kq_submap *pom, *max; 107: kq_color *c; 108: float z; 109: 110: max = NULL; 111: for(pom = prvsubmap; pom; pom = pom->next){ 112: c = smpixel(pom, x,y); 113: if(c && (max == NULL || c->z+pom->z > z)){ 114: z = c->z+pom->z; 115: max = pom; 116: } 117: } 118: 119: return max; 120: }
Funkce smpixel vrátí políčko submapy podle souřadnic hlavní mapy. map.c 310: kq_color *smpixel (kq_submap *sm, int x, int y) 311: { 312: return mappixel(sm->map, x-sm->x, y-sm->y); 313: }
Funkce najdibarvu vrátí nejvyšší submapu, která obsahuje určitou barvu na daných souřadnicích hlavní mapy. kq_submap *nejvyssipix(): 60 kq_color *smpixel(): 60–61, 185, 213–214, 220, 238, 240–241 kq_submap *najdibarvu(): 61, 209, 215
60
19 Modul map
Program kraluk map.c
315: kq_submap *najdibarvu (kq_color *col, int x, int y) 316: { 317: kq_submap *pom; 318: 319: for(pom = prvsubmap; pom; pom = pom->next) 320: if(col == smpixel(pom, x,y)) return pom; 321: 322: return NULL; 323: }
Ve struktuře kq_submap je také položka hide, která stejně jako u widgetů určuje, zda je submapa schovaná. Schované submapy (hide = 1) nejsou v seznamu prvsubmap, ale v seznamu prvhidsm. To je důvod, proč funkce zaradsubmap a vyradsubmap mají parametr, který seznam mají použít. Schované submapy nejsou v mapě, ale je možné narozdíl o zobrazených submap jim měnit souřadnice. Funkce hidesubmap schová submapu. map.c 325: void hidesubmap (kq_submap *sm) 326: { 327: if(sm == bgmap){ 328: warning("hidesubmap(bgmap)"); 329: return; 330: } 331: 332: if(sm->hide) return; 333: 334: vyradsubmap(sm, &prvsubmap); 335: if(autoreloadmap) zrussubmap(sm); 336: 337: sm->hide = 1; 338: 339: sm->next = prvhidsm; 340: prvhidsm = sm; 341: }
Funkce unhidesubmap odschová submapu. map.c 343: void unhidesubmap (kq_submap *sm) 344: { 345: if(sm == bgmap){ 346: warning("unhidesubmap(bgmap)"); 347: return; 348: } 349: 350: if(!sm->hide) return; 351: 352: vyradsubmap(sm, &prvhidsm); 353: 354: sm->hide = 0; 355: 356: zaradsubmap(sm, &prvsubmap); 357: if(autoreloadmap) pouzijsubmap(sm); 358: }
Funkce deletelsubmaps smaže všechny submapy, které mají kladnou položku lokalni a schová ty, které mají položku lokalni zápornou. Beze změny tedy zůstanou jen ty, kde je položka lokalni nulová. Tato funkce je spuštěna při přechodu na jiné políčko. map.c 383: void deletelsubmaps () 384: { 385: kq_submap **pom, *pomo, *pomoc; 386: char trebarel; 387: 388: if(bgmap -> lokalni){ 389: warning("deletelsubmaps: lokalni bgmap"); kq_submap *prvhidsm: 57–58, 61–62, 139–140, 143, 147–148 void hidesubmap(): 61, 66, 69, 79, 173, 220 void unhidesubmap(): 61, 66, 69, 79–80, 174, 220, 238 void deletelsubmaps(): 61, 173
61
19 Modul map 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: }
Program kraluk
bgmap->lokalni = 0; } for(pom = &prvhidsm;; pom = &pomo->next){ for(pomo = *pom; pomo && pomo->lokalni > 0; pomo = pomoc){ pomoc = pomo->next; freesm(pomo); } *pom = pomo; if(!pomo) break; } trebarel = 0; for(pom = &prvsubmap;; pom = &pomo->next){ for(pomo = *pom; pomo && pomo->lokalni; pomo = pomoc){ pomoc = pomo->next; trebarel = 1; if(pomo->lokalni > 0) freesm(pomo); else{ pomo->next = prvhidsm; prvhidsm = pomo; } } *pom = pomo; if(!pomo) break; } if(autoreloadmap && trebarel) reloadmap();
Funkce deleteAsubmaps smaže všechny submapy. Je zavolána při načtení pozice nebo při restartu. map.c 422: void deleteAsubmaps () 423: { 424: kq_submap *pom; 425: 426: while(prvsubmap){ 427: pom = prvsubmap->next; 428: freesm(prvsubmap); 429: prvsubmap = pom; 430: } 431: while(prvhidsm){ 432: pom = prvhidsm->next; 433: freesm(prvhidsm); 434: prvhidsm = pom; 435: } 436: 437: bgmap = NULL; 438: if(autoreloadmap){ 439: free(mapa_z); 440: free(mapa.pole); 441: mapa_z = NULL; 442: mapa.pole = NULL; 443: } 444: }
Způsob, jak chápat hlavní mapu na obrázku je dán proměnnými map_xa, map_xb, map_ya, map_yb. Políčko mapy, které má souřadnice x, y, má na obrázku (ve win) souřadnice: x*map_xa+map_xb,
y*map_ya+map_yb.
void deleteAsubmaps(): 62, 147, 188 int map_xa: 62, 67, 168, 171 int map_ya: 62, 67, 168, 171 int map_yb: 62, 67, 168, 171, 183
62
int map_xb: 62, 67, 168, 171, 183
20 Modul post
Program kraluk
20 Modul post Tento modul spojuje widgety a submapy do jedné struktury, která se jmenuje kq_postava. post.h 18: struct kq_postava{ 19: int x,y,xx,yy; 20: kq_timer *tim; 21: char zdi, barvy, odraz, odejde; 22: 23: kq_submap *submap; 24: int sm_x, sm_y; 25: 26: char autou_typ; 27: union{ 28: kq_postava *sledpost; 29: struct{ 30: int x, y; 31: } sourad; 32: } auto_u; 33: 34: int chyt_vzdal; 35: void (*chyt_func)(kq_postava *post); 36: 37: void (*auto_func)(kq_postava *post); 38: kq_timer *auto_tim; 39: 40: void (*free_func)(kq_postava *post); 41: 42: kq_animpost *animace; 43: char smer; 44: int animstav; 45: kq_timer *animtim; 46: 47: kq_widget *widget; 48: 49: float xz, yz, z; 50: 51: char lokalni, hide, zmena; 52: kq_postava *next; 53: int Cislo; 54: };
Postavy jsou pomocí položky next řazeny do zásobníku začínajícím postavou prvpost. post.c 18: kq_postava *prvpost = NULL;
Položky x a y udávají souřadnice postavy na mapě mapa. Položky xx a yy udávájí rychlost postavy. Konkrétně vždy, když je na postavu zavolána funkce jdipost, přičte k položce x položku xx a k položce y položku yy. Další položka je tim. Tato položka může obsahovat libovolný timer, ale obvykle obsahuje timer, který opakovaně volá funkci jdipost na tuto postavu. Další čtyři položky jsou pravdivostní hodnoty. Položka zdi zmamená, že postava nemůže chodit přes barvy, které mají položku zed nastavenu na true. Položka barvy znamená, že je při posunutí postavy zavolána funkce spustfb. Položka odraz znamená, že když postava nemůže jít tam, kam by měla. nezastaví se, ale jde na opačnou stranu. Položka odejde znamená, že může postava přejít na jinou obrazovku. V případě, že je postava lokální, je tak zrušena nebo schována. Jinak je změněno aktuální políčko. Položka odraz je implicitně nastavena na false. Ostatní položky (zdi, barvy a odejde) jsou implicitně nastaveny na true. Postava může mít pointer na submapu v položce submap. Položky sm_x a sm_y udávají, kde je v submapě střed postavy. Nastavit submapu postavy je možné funkcí post_submap. kq_postava: 6–7, 53, 63–69, 71, 73, 75–76, 79, 136, 138–139, 141, 143, 145, 148, 152–153, 172–173, 175–176, 181, 203–204, 215, 218–225, 227–228, 232, 235–236, 238, 246 kq_postava *prvpost: 63, 66–68, 139, 141, 143, 148, 204, 212, 234, 236 void post_submap(): 64, 175–176, 184, 224, 226, 229
63
20 Modul post
Program kraluk post.c
487: void post_submap (kq_postava *post, char *nazev, int x, int y, float z) 488: { 489: if(post->submap) znicsubmap(post->submap); 490: 491: post->sm_x = x; 492: post->sm_y = y; 493: post->submap = vytvorsubmap(post->x-x, post->y-y, z, nazev, post->lokalni, post->hide); 494: }
Každá postava má nějaký cíl, tedy to, kam chce dojít. Implicitně to je políčko se souřadnicemi 0,0. Tento cíl může být dán buď souřadnicemi mapy nebo postavou, kterou chce tato postava dohnat. Položka autou_typ určuje, co z těchto možností to je. Může nabývat jednu z následujících možností: post.h 1: #define AUTOU_SOUR 2: #define AUTOU_POST
0 // souradnice 1 // postava
Následuje samotný union obsahující potřebné informace. Funkcí setchytsour nastavím souřadnice cíle. post.c 524: void setchytsour (kq_postava *post, int x, int y) 525: { 526: post->autou_typ = AUTOU_SOUR; 527: post->auto_u.sourad.x = x; 528: post->auto_u.sourad.y = y; 529: }
Funkcí setchytpost nastavím postavu, kterou chce postava chytit. post.c 531: void setchytpost (kq_postava *post, kq_postava *sledpost) 532: { 533: post->autou_typ = AUTOU_POST; 534: post->auto_u.sledpost = sledpost; 535: }
Funkce getchytsour pak získá souřadnice cíle. post.c 506: void getchytsour (kq_postava *post, int *x, int *y) 507: { 508: if(post->autou_typ == AUTOU_SOUR){ 509: if(x) *x = post->auto_u.sourad.x; 510: if(y) *y = post->auto_u.sourad.y; 511: return; 512: } 513: if(post->autou_typ == AUTOU_POST){ 514: if(x) *x = post->auto_u.sledpost->x; 515: if(y) *y = post->auto_u.sledpost->y; 516: return; 517: } 518: 519: warning("neznamy typ souradnic: %d", post->autou_typ); 520: if(x) x = 0; 521: if(y) y = 0; 522: }
Další položkou postavy je chyt_vzdal, minimální vzdálenost při které se spustí funkce chyt_func, která je další položkou postavy. Implicitní chyt_vzdal je nula a implicitní funkce chyt_func je NULL. Funkce zkuschytit otestuje, zda je postava svému cíli dostatečně blízko a případně spustí chyt_func. post.c 299: void zkuschytit (kq_postava *post) 300: { 301: int x, y; 302: 303: if(post->chyt_func && !post->hide){ 304: getchytsour(post, &x, &y); AUTOU_SOUR: 64, 142, 152, 226 AUTOU_POST: 64, 153 void setchytsour(): 64, 67, 204, 215, 233, 235–236 void setchytpost(): 64, 204, 225, 228, 234 void getchytsour(): 64, 75, 79, 232 void zkuschytit(): 64, 66, 69
64
20 Modul post
Program kraluk
305: if(post->chyt_vzdal >= vzdalenost(x,y,post->x, post->y)) 306: post->chyt_func(post); 307: } 308: }
Další položkou je auto_func, což je funkce pro automatické ovládání postavy. Tato funkce se může spustit buď vždy, když se spustí funkce jdipost na tuto postavu, a nebo jednou za určitý časový interval. V druhém případě je v položce auto_tim timer, který opakovaně funkci spouští. Že má být auto_func spuštena při jdipost, se pozná podle toho, že auto_tim je NULL. Funkce autopost přiřadí postavě její auto_func, případně založí timer s prioritopu AUTOPRIOR. Dostane postavu, pak tu funkci, potom čas, po kterém se má funkce poprvé spustit a nakonec čas, po kterém se spouští opakovaně. V případě, že je poslední parametr nulový, nezakládá vůbec timer a tedy ignoruje i předposlední parametr. Nejčastěji jsou této funkci předávány funkce z modulu autopost. post.c 537: void autopost (kq_postava *post, void (*auto_func)(kq_postava *post), int prvcas, int cas) 538: { 539: if(post->auto_tim) znictimer(post->auto_tim); 540: 541: post->auto_func = auto_func; 542: if(auto_func != NULL && cas){ 543: post->auto_tim = vytvortimer(auto_func, pinpointer(post), prvcas, 544: AUTOPRIOR, 0, post->lokalni, post->hide); 545: post->auto_tim->cas = cas; 546: } 547: else post->auto_tim = NULL; 548: }
Další položkou struktury kq_postava je funkce free_func. Tato funkce je zavolána těsně před uvolněním postavy z paměti. Není však možné, aby tato funkce onomu uvolnění zabránila. Položky animace, smer, animstav a animtim určují pixmapu, která bude pro postavu použita a budou blíže vysvětleny u datového typu kq_animpost. Položka widget je ukazatel na widget připadající postavě. Tento widget existuje od začátku postavy, ale má na začátku NULLovou pixmapu. Další tři položky xz, yz a z určují Z-kovou souřadnici postavy. Z těchto údajů a souřadnic postavy se Z-ková souřadnice spočítá funkcí spocti_z takto: post.c 118: static float spocti_z (kq_postava *post) 119: { 120: return post->xz*post->x + post->yz*post->y + post->z; 121: }
Pro zjednodušení ukládání položek xz, yz a z mám funkci post_z. post.c 496: void post_z (kq_postava *post, float xz, float yz, float z) 497: { 498: post->xz = xz; 499: post->yz = yz; 500: post->z = z; 501: 502: post->zmena = 1; 503: menpost = 1; 504: }
Další položky jsou lokalni a hide, které jsou s podobným účelem i v dalších strukturách (kq_widget, kq_submap, v kq_timer je místo hide položka pause). Tyto položky se dědí z postavy do struktur, které obsahuje (ačkoliv nepoužívám C++). Pro schování a odschování postavy jsou funkce hidepost a unhidepost. Postavy však narozdíl od ostatních struktur nemají pro schované postavy speciální seznam.
void autopost(): 65, 204, 214–215, 226, 228, 230, 232–233, 235–236 int AUTOPRIOR: 11, 65 float spocti_z(): 65, 67, 71 void post_z(): 65, 68, 176, 209, 218, 220, 224, 230–233, 235 void hidepost(): 66, 70, 209, 221 void unhidepost(): 66, 209, 216, 222, 226, 230–232
65
20 Modul post
Program kraluk post.c
413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434:
void hidepost (kq_postava *post) { post->hide = 1; if(post->submap) hidesubmap(post->submap); if(post->tim) pausetimer(post->tim); if(post->animtim) pausetimer(post->animtim); if(post->auto_tim) pausetimer(post->auto_tim); zmenapost(post); } void unhidepost (kq_postava *post) { post->hide = 0; if(post->submap) unhidesubmap(post->submap); if(post->tim) unpausetimer(post->tim); if(post->animtim) unpausetimer(post->animtim); if(post->auto_tim) unpausetimer(post->auto_tim); zkuschytit(post); zmenapost(post); }
Je třeba si však uvědomit, že položka lokalni není tak snadno měnitelná jako v ostatních strukturách. Změnou této položky totiž nejsou změněny položky lokalni v timerech, widgetu, a submapě, kterou tato postava obsahuje. Funkce, která smaže všechny lokální postavy se těmito strukturami totiž nezabývá, protože předpokládá, že už tyto struktury vyřešily funkce patřící oněm strukturám. Funkce, která smaže lokální postavy se jmenuje deletelposts. post.c 457: void deletelposts () 458: { 459: kq_postava **pom, *pomo, *pomoc; 460: 461: for(pom = &prvpost;; pom = &pomo->next){ 462: for(pomo = *pom; pomo && pomo->lokalni > 0; pomo = pomoc){ 463: pomoc = pomo->next; 464: if(pomo->free_func) pomo->free_func(pomo); 465: free(pomo); 466: } 467: *pom = pomo; 468: if(!pomo) break; 469: if(pomo->lokalni < 0){ 470: pomo->hide = 1; 471: zmenapost(pomo); 472: } 473: } 474: }
Jelikož se snažím šetřit s grafickými operacemi, nezměním widget postavy okamžitě po změně postavy, ale pouze si označím postavu jako pozměněnou tím, že do její položky zmena dosadím true a navíc zapíšu true do proměnné menpost. Tuto operaci udělá funkce zmenapost. post.c 19: char menpost = 0; post.c 257: void zmenapost (kq_postava *post) 258: { 259: menpost = 1; 260: post->zmena = 1; 261: }
Na konci každého framu je pak zavolána funkce updateposts, která v případě, že menpost je true projde všechny postavy a upraví widgety těch, které mají položku zmena pravdivou. Zároveň tuto položku vynuluje a nakonec vynuluje i proměnnou mengraf. void deletelposts(): 66, 173 207–208, 222, 229, 238–239, 241
void menpost: 65–67, 148 void zmenapost(): 66, 69–71, 73, 174, void updateposts(): 24–25, 67, 121
66
20 Modul post
Program kraluk post.c
263: void updateposts () 264: { 265: kq_pixmap *pix; 266: int x, y; 267: float z; 268: kq_postava *pom; 269: 270: if(!menpost) return; 271: for(pom = prvpost; pom; pom = pom->next) 272: if(pom->zmena){ 273: if(pom->hide){ 274: hidewidget(pom->widget); 275: continue; 276: } 277: if(pom->animace){ 278: x = pom->x * map_xa + map_xb - pom->animace->x; 279: y = pom->y * map_ya + map_yb - pom->animace->y; 280: z = spocti_z(pom); 281: if(pom->animace->framu == 1 && pom->animace->jednopol) 282: pix = pom->animace->pix.map; 283: else{ 284: if(pom->animace->jednopol) pix = pom->animace->pix.pole[pom->animstav]; 285: else pix = pom->animace->pix.pole[pom->smer*pom->animace->framu + pom->animstav]; 286: } 287: zmenwidget(pom->widget, x, y, z, pix); 288: } 289: else prebarviwidget(pom->widget, NULL); 290: 291: if(!pom->hide) unhidewidget(pom->widget); 292: 293: pom->zmena = 0; 294: } 295: 296: menpost = 0; 297: }
Funkce vytvorpost založí novou postavu a vrátí ukazatel na ni. Přitom, pokud do parametru tim dostane větší číslo než nula, založí timer, který každých tim framů zavolá funkci jdipost na příslušnou postavu. Parametr tprior určuje post.c 207: kq_postava *vytvorpost (int x, int y, int smer, int tim, 208: float tprior, char lokalni, char hide) 209: { 210: kq_postava *vysledek; 211: 212: vysledek = (kq_postava *)mymalloc(sizeof(kq_postava)); 213: vysledek->x = x; 214: vysledek->y = y; 215: vysledek->xx = 0; 216: vysledek->yy = 0; 217: vysledek->zdi = 1; 218: vysledek->odraz = 0; 219: vysledek->barvy = 1; 220: vysledek->odejde = 1; 221: vysledek->submap = NULL; 222: vysledek->sm_x = 0; 223: vysledek->sm_y = 0; 224: 225: setchytsour(vysledek, 0, 0); 226: 227: vysledek->chyt_vzdal = 0; 228: vysledek->chyt_func = NULL; 229: 230: vysledek->auto_func = NULL; 231: vysledek->auto_tim = NULL; 232: 233: vysledek->free_func = NULL;
67
20 Modul post 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: }
Program kraluk
vysledek->animace = NULL; vysledek->smer = smer; vysledek->animstav = 0; vysledek->animtim = NULL; post_z(vysledek, 0, 0, 0); vysledek->lokalni = lokalni; vysledek->hide = hide; vysledek->zmena = 0; vysledek->widget = vytvorwidget(0, 0, 0, NULL, lokalni, hide); if(tim > 0) vysledek->tim = vytvortimer(&jdipost, pinpointer(vysledek), tim, tprior, 0, lokalni, hide); else vysledek->tim = NULL; vysledek->next = prvpost; prvpost = vysledek; return vysledek;
Funkce znicpost smaže postavu včetně všech struktur, které obsahuje. Tuto funkci je třeba používat opatrně. Pokud totiž je zničena postava uvnitř funkce, která s touto funkcí manipuluje, není zaručeno, že se program bude chovat korektně. Je tedy jistější v takových případech vytvořit timer, který se spustí za nula framů a danou postavu zničí. post.c 436: void znicpost (kq_postava *post) 437: { 438: kq_postava **pom; 439: 440: if(post->submap) znicsubmap(post->submap); 441: if(post->tim) znictimer(post->tim); 442: if(post->animtim) znictimer(post->animtim); 443: if(post->auto_tim) znictimer(post->auto_tim); 444: znicwidget(post->widget); 445: 446: for(pom = &prvpost; *pom && *pom!=post; pom = &((*pom)->next)); 447: if(*pom){ 448: *pom = post->next; 449: if(post->free_func) post->free_func(post); 450: free(post); 451: } 452: else{ 453: warning("znicpost: postava nenalezena v seznamu"); 454: } 455: }
Funkce deleteAposts uvolní z paměti všechny postavy. post.c 476: void deleteAposts () 477: { 478: kq_postava *pom; 479: 480: while(prvpost){ 481: pom = prvpost->next; 482: free(prvpost); 483: prvpost = pom; 484: } 485: }
Funkce posunpost změní souřadnice postavy. To však provede pouze v případě, že zadané souřadnice jsou uvnitř mapy a postavička na ně může vejít (není to zeď nebo postava může na zdi. Potom tato funkce spustí funkce barev, tedy spustfb. Pokud se posun podaří, vrátí true, pokud ne, vrátí false. void znicpost(): 68, 70, 184, 204, 211–212, 214–215, 217, 222–224, 226, 232–234, 238–239 void deleteAposts(): 68, 148, 188 void posunpost(): 69–70, 173, 221–222, 228, 232, 237, 239–241
68
20 Modul post
Program kraluk post.c
310: int posunpost (kq_postava *post, int x, int y) 311: { 312: int ohide; 313: kq_color *nbarva, *obarva; 314: char navrat; 315: 316: if(x<0 || x>=mapa.sirka || y<0 || y>=mapa.vyska) return 0; 317: 318: navrat = 1; 319: 320: if(mapa_z){ 321: if(post->submap){ 322: ohide = post->submap->hide; 323: hidesubmap(post->submap); 324: } 325: obarva = mappixel(mapa, post->x, post->y); 326: nbarva = mappixel(mapa, x, y); 327: if(mappixel(mapa, x,y)->zed && post->zdi) navrat = 0; 328: else{ 329: post->x = x; 330: post->y = y; 331: if(post->submap){ 332: post->submap->x = x-post->sm_x; 333: post->submap->y = y-post->sm_y; 334: } 335: } 336: if(post->submap && !ohide) unhidesubmap(post->submap); 337: 338: if(post->barvy) spustfb(post, nbarva, obarva); 339: } 340: else{ 341: post->x = x; 342: post->y = y; 343: } 344: 345: if(navrat){ 346: zmenapost(post); 347: zkuschytit(post); 348: } 349: 350: return navrat; 351: }
Funkce jdipost je opakovaně spouštěna timerem, v případě, že při vytvoření postavy byl funkci vytvorpost předán kladný parametr tim. Funkce jdipost nejprve spustí funkci pro automatický pohyb, potom posune postavu o xx a yy a nakonec posune animaci postavy. Kromě toho tato funkce nastaví podle xx ayy položku smer. Při počítání položky smer má položka xx větší prioritu než yy. Pokud by postava měla odejít z mapy, tak v případě, že postava není lokální, změní políčko (obrazovku). Jinak je postava schována (lokalni < 0) nebo zničena (lokalni > 0). post.c 353: void jdipost (kq_postava *post) 354: { 355: char smer, sel; 356: int x, y; 357: 358: if(post->auto_func && !post->auto_tim) post->auto_func(post); 359: 360: if(post->xx || post->yy){ 361: if(post->xx < 0) smer = VLEVO; 362: else if(post->xx > 0) smer = VPRAVO; 363: else if(post->yy < 0) smer = NAHORU; 364: else if(post->yy > 0) smer = DOLU; 365: 366: if(post->smer != smer){ void jdipost(): 63, 65, 67–69, 71, 159, 236, 238
69
20 Modul post
Program kraluk
367: post->smer = smer; 368: zmenapost(post); 369: } 370: 371: x = post->x + post->xx; 372: y = post->y + post->yy; 373: 374: if(mapa_z && (x<0 || x>=mapa.sirka || y<0 || y>=mapa.vyska)){ 375: if(post->odejde){ 376: if(post->lokalni){ 377: if(post->lokalni > 0){ 378: znicpost(post); 379: return; 380: } 381: else hidepost(post); 382: sel = 0; 383: } 384: else{ 385: if(x<0) sel = polvedle(post, VLEVO); 386: else if(x>=mapa.sirka) sel = polvedle(post, VPRAVO); 387: else if(y<0) sel = polvedle(post, NAHORU); 388: else sel = polvedle(post, DOLU); 389: } 390: } 391: else sel = 0; 392: } 393: else sel = posunpost(post, x, y); 394: if(!sel){ 395: if(post->odraz){ 396: if(x<0 || x>=mapa.sirka) post->xx *= -1; 397: else if(y<0 || y>=mapa.vyska) post->yy *= -1; 398: else{ 399: post->xx *= -1; 400: post->yy *= -1; 401: } 402: } 403: else{ 404: post->xx = 0; 405: post->yy = 0; 406: } 407: } 408: } 409: 410: if(!post->animtim) anip_step(post); 411: }
Postavě se nepřiřazuje jen jedna pixmapa, ale souhrn pixmap, které mají být použity. Onen souhrn je struktura kq_animpost, která se uloží do položky animace v postavě. post.h 4: struct kq_animpost{ 5: int x,y; 6: union{ 7: kq_pixmap **pole; 8: kq_pixmap *map; 9: } pix; 10: int framu, tim; 11: char jednopol, porad; 12: 13: char lokalni; 14: kq_animpost *next; 15: int Cislo; 16: };
Položky x a y určují souřadnice v pixmapě, kde se nalézá postava. Po zjištění souřadnic postavy se tedy ještě odečtou tyto souřadnice a tam se teprve umístí onen widget. kq_animpost: 7, 63, 65, 70–74, 136, 138–139, 141, 143, 145, 148, 151–152, 203, 218, 222, 225, 227, 235
70
20 Modul post
Program kraluk
V položce pix.pole se nalézá pole ukazatelů na pixmapu. Pokud by však toto pole mělo mít jen jeden prvek, je místo zakládání pole rovnou uložena pixmapa do pix.map. Počet prvků pole určuje položka framu spolu s položkou jednopol. Pokud je jednopol true, udává položka framu rovnou počet prvků pole a při posouvání postavy se tyto prvky pravidelně střídají: 0, 1, 2, ..., framu-1, 0, 1, ... Když je jednopol záporné, nestřídají se podle času, ale podle desetinásobku Z-kové souřadnice postavy. Když je Z-ková souřadnice nulová, použije se pix.pole[0], když to je 0.1, tak se použije pix.pole[1], . . . a když je Z-ková souřadnice rovná framu/10, použije se opět pix.pole[0]. Pokud však je jednopol false, je prvků pole čtyřikrát víc, protože má postava pro každý směr jiné pixmapy. V položce smer může být číslo od nuly do tří, což je buď VLEVO, VPRAVO, NAHORU nebo DOLU V takovém případě se pixmapy střídají takto:
framu*smer, framu*smer+1, framu*smer+2, ..., framu*smer+(framu-1), framu*smer, ... Položka porad v struktuře kq_animpost určuje, zda má být položka animována, i když stojí. Položka tim určuje, jak rychle má být animace postavy prováděna. Při přiřazení animace postavě, je do položky animtim v postavě uložen timer s prioritou ANIMPRIOR, který posune animaci, tedy spustí funkci anip_step. Pokud je položka tim nulová, je posunuta animace při každém zavolání funkce jdipost. Aktuální pixmapa, která má být použita, je určena položkou animstav. Tato položka je číslo mezi nulou a framu-1. Aktuální směr tedy tuto položku neovlivňuje. Animaci postavy posune funkce anip_step, které se předá ukazatel na danou postavu. post.c 123: void anip_step (kq_postava *post) 124: { 125: if(!post->animace || post->animace->framu == 1) return; 126: if(!post->animace->porad && !post->xx && !post->yy) return; 127: 128: if(post->animace->jednopol < 0){ 129: post->animstav = ((int)(spocti_z(post)*10)) % post->animace->framu; 130: if(post->animstav < 0) post->animstav += post->animace->framu; 131: } 132: 133: post->animstav++; 134: if(post->animstav >= post->animace->framu) post->animstav = 0; 135: 136: zmenapost(post); 137: }
Položka lokalni ve struktuře kq_animpost udává, že bude tato struktura smazána a pomocí položky next jsou všechny animace postav zařazeny do zásobníku, který začíná proměnou prvanip. post.c 17: kq_animpost *prvanip = NULL;
Funkce nactianip založí novou strukturu kq_animpost a načte do nich ze souborů obrázky podle názvu, který dostane. Nakonec vrátí ukazatel na nově založenou strukturu. Pokud má načíst jen jednu pixmapu, přečte si jednoduše daný název s příponou xpm v adresáři s animacemi postav. Jinak předpokládá, že název, který funkce dostala, je název adresáře, ve kterém jsou pixmapy uloženy. Pokud je jednopol true, tak zde vyžaduje soubory: anim0.xpm, anim1.xpm, anim2.xpm, . . . Jinak zde jsou soubory: up0.xpm, up1.xpm, . . ., left0.xpm, left1.xpm, . . ., right0.xpm, right1.xpm, . . ., down0.xpm, down1.xpm, . . . V případě, že framu == 0, nejsou použity soubory up0.xpm, left0.xpm, . . ., ale jenom: up.xpm, down.xpm, left.xpm, right.xpm. post.c 21: kq_animpost *nactianip (int x, int y, char *nazev, int framu, int tim, 22: char jednopol, char porad, char lokalni) 23: { 24: int i, pocetpix; 25: char cistr[20], *fullname; int ANIMPRIOR: 11, 73 void anip_step(): 70–71, 73, 159, 209, 238 175–176, 184, 203, 214, 222, 224–225, 228–229, 235–236, 243
71
kq_animpost *nactianip(): 71,
20 Modul post 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93:
Program kraluk
kq_animpost *vysledek; if(framu < 1){ warning("nactianip: framu=%d < 1 framu = 1; }
==>
framu=1", framu);
vysledek = (kq_animpost *)mymalloc(sizeof(kq_animpost)); vysledek->x = x; vysledek->y = y; vysledek->framu = framu; vysledek->tim = tim; vysledek->jednopol = jednopol; vysledek->porad = porad; vysledek->lokalni = lokalni; if(jednopol) pocetpix = framu; else pocetpix = framu*4; if(pocetpix > 1) vysledek->pix.pole = (kq_pixmap **)mymalloc(pocetpix * sizeof(kq_pixmap *)); if(jednopol){ if(framu > 1) for(i = 0; i < framu; i++){ sprintf(cistr, "%d", i); fullname = joinstrings(ANIPDIR, nazev, ANIPSTR, cistr, NULL); vysledek->pix.pole[i] = nactikqXPM(fullname, lokalni); free(fullname); } else{ fullname = joinstrings(ANIPDIR, nazev, NULL); vysledek->pix.map = nactikqXPM(fullname, lokalni); } } else{ for(i = framu*NAHORU; i < (NAHORU+1)*framu; i++){ if(framu == 1) cistr[0] = 0; else sprintf(cistr, "%d", i - framu*NAHORU); fullname = joinstrings(ANIPDIR, nazev, UPSTR, cistr, NULL); vysledek->pix.pole[i] = nactikqXPM(fullname, lokalni); free(fullname); } for(i = framu*DOLU; i < (DOLU+1)*framu; i++){ if(framu == 1) cistr[0] = 0; else sprintf(cistr, "%d", i - framu*DOLU); fullname = joinstrings(ANIPDIR, nazev, DOWNSTR, cistr, NULL); vysledek->pix.pole[i] = nactikqXPM(fullname, lokalni); free(fullname); } for(i = framu*VLEVO; i < (VLEVO+1)*framu; i++){ if(framu == 1) cistr[0] = 0; else sprintf(cistr, "%d", i - framu*VLEVO); fullname = joinstrings(ANIPDIR, nazev, LEFTSTR, cistr, NULL); vysledek->pix.pole[i] = nactikqXPM(fullname, lokalni); free(fullname); } for(i = framu*VPRAVO; i < (VPRAVO+1)*framu; i++){ if(framu == 1) cistr[0] = 0; else sprintf(cistr, "%d", i - framu*VPRAVO); fullname = joinstrings(ANIPDIR, nazev, RIGHTSTR, cistr, NULL); vysledek->pix.pole[i] = nactikqXPM(fullname, lokalni); free(fullname); } }
72
20 Modul post
Program kraluk
94: 95: vysledek->next = prvanip; 96: prvanip = vysledek; 97: 98: return vysledek; 99: }
Funkce zmenanip nastaví postavě její animaci. post.c 101: void zmenanip (kq_postava *post, kq_animpost *anip) 102: { 103: if(anip == post->animace) return; 104: 105: if(post->animtim) znictimer(post->animtim); 106: post->animtim = NULL; 107: post->animace = anip; 108: if(anip){ 109: if(anip->tim > 0){ 110: post->animtim = vytvortimer(&anip_step, pinpointer(post), anip->tim, ANIMPRIOR, 111: 0, post->lokalni, post->hide); 112: } 113: post->animstav %= anip->framu; 114: } 115: zmenapost(post); 116: }
Funkce freeanip uvolní animaci postavy z paměti a současně i pixmapy, které se v ní nalézají. Tuto funkci není dobré použít bezprostředně po odebrání dané animace určité postavě, protože pixmapa zůstává přidělena widgetu do konce jednoho framu. post.c 139: void freeanip (kq_animpost *anip) 140: { 141: int i; 142: kq_animpost **pom; 143: 144: for(pom = &prvanip; *pom && *pom != anip; pom = &(*pom)->next); 145: if(!pom){ 146: warning("freeanip: animace postavy nenalezena v seznamu"); 147: return; 148: } 149: *pom = anip->next; 150: 151: i = anip->framu; 152: if(!anip->jednopol) i *= 4; 153: 154: if(i == 1) freekqPixmap(anip->pix.map); 155: else if(i > 1){ 156: while(i) freekqPixmap(anip->pix.pole[--i]); 157: free(anip->pix.pole); 158: } 159: free(anip); 160: }
Funkce deletelanips smaže všechny kq_animpost, které mají položku lokalni nastavenou na true. post.c 162: void deletelanips () 163: { 164: kq_animpost **pom, *pomo, *pomoc; 165: 166: for(pom = &prvanip;; pom = &pomo->next){ 167: for(pomo = *pom; pomo && pomo->lokalni; pomo = pomoc){ 168: pomoc = pomo->next; 169: if(pomo->framu > 1 || (pomo->framu == 1 && !pomo->jednopol)) 170: free(pomo->pix.pole); void zmenanip(): 73, 176, 184, 190, 204, 209, 211, 214, 216, 219, 221–224, 226, 228–231, 235–236, 238–239 void freeanip(): 73 void deletelanips(): 73, 173
73
21 Modul autopost
Program kraluk
171: free(pomo); 172: } 173: *pom = pomo; 174: if(!pomo) break; 175: } 176: }
Funkce deleteAanips smaže úplně všechny kq_animpost. post.c 178: void deleteAanips () 179: { 180: kq_animpost *pom; 181: 182: while(prvanip){ 183: pom = prvanip->next; 184: if(prvanip->framu > 1 || (prvanip->framu == 1 && !prvanip->jednopol)) 185: free(prvanip->pix.pole); 186: free(prvanip); 187: prvanip = pom; 188: } 189: }
Animace postav (kq_animpost) se dají zafixovat podobně jako pixmapy (kq_pixmap pomocí fix_pix). Funkce fix_anips převede všechny dosud načtené animace do seznamu fixed_anips, čímž zruší možnost je mazat a také tak nejsou ukládány do souboru s uloženou pozicí. Přitom uloží počet animací, které takto zafixovala do proměnné pocet_fixanips. Nakonec tato funkce zavolá fix_pix, čímž zafixuje pixmapy. Tato funkce by tedy neměla být spouštěna vícenásobně ani by neměla být spuštěna v případě, že je jindy spuštěna funkce fix_pix. post.c 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205:
kq_animpost *fixed_anips = NULL; int pocet_fixanips = 0; void fix_anips () { kq_animpost *pom; if(pocet_fixanip) warning("funkce fix_anips() je spustitelna jen jednou"); for(pom = prvanip; pom; pom = pom->next) pom->Cislo = --pocet_fixanip; fixed_anips = prvanip; prvanip = NULL; fix_pix(); }
21 Modul autopost V tomto modulu jsou funkce, které je možné použít pro automatický pohyb postavy. Funkce randomsmer uloží do svých parametrů náhodný, šikmý nebo rovný směr. autopost.c 9: void randomsmer (int *xx, int *yy) 10: { 11: int smer; 12: 13: smer = rand()%8; 14: 15: if(smer > 3) smer++; 16: 17: if(xx) *xx = smer%3-1; 18: if(yy) *yy = smer/3-1; 19: }
void deleteAanips(): 74, 148, 188 void fix_anips(): 74, 243 int pocet_fixanips: 74 void randomsmer(): 74–75
74
kq_animpost *fixed_anips: 74, 152
21 Modul autopost
Program kraluk
Pravda, tato funkce se ještě jako funkce pro automatický pohyb postavy použít nedá, protože má jakožto parametr dvě celá čísla a ne postavu. Funkce auto_random tedy má parametr postavu a k určení směru použije randomsmer. autopost.c 21: void auto_random (kq_postava *post) 22: { 23: randomsmer(&post->xx, &post->yy); 24: }
Funkce primosmer uloží do proměnných xx a yy směr podle parametrů x a y. Parametry x a y jsou relativní souřadnice cíle, kam se chce postava dostat, podle postavy. Funkce se snaží postavu co nejpřesněji nasměrovat na cíl. Šikmý směr je použit v okamžiku, kdy není žádná souřadnice dvakrát větší než druhá. autopost.c 26: void primosmer (int *xx, int *yy, int x, int y) 27: { 28: if(x==0 && y==0){ 29: *xx = 0; 30: *yy = 0; 31: return; 32: } 33: 34: if(xx){ 35: if(2*abs(x) > abs(y)){ 36: if(x > 0) *xx = 1; 37: else *xx = -1; 38: } 39: else *xx = 0; 40: } 41: 42: if(yy){ 43: if(2*abs(y) > abs(x)){ 44: if(y > 0) *yy = 1; 45: else *yy = -1; 46: } 47: else *yy = 0; 48: } 49: }
Podobně jako u funkce randomsmer i zde je funkce, která aplikuje funkci primosmer na postavu. Tato funkce se jmenuje auto_primo. autopost.c 51: void auto_primo (kq_postava *post) 52: { 53: int x, y; 54: 55: getchytsour(post, &x, &y); 56: primosmer(&post->xx, &post->yy, x-post->x, y-post->y); 57: }
Tyto algoritmy ještě nejsou ideální, protože by bylo někdy žádoucí, aby postava při sledování svého cíle obcházela zdi. Takový algoritmus nazvu chytrým. Budu předpokládat, že bude chytrý algoritmus spuštěn při každém posunutí postavy, aby mohl svou postavu zcela ovládat. Pokaždé by však měl znovu vypočítat směr bez toho, aby si udržoval z minula nějaké výpočty. To proto, že bych zaprvé tyto výpočty musel ukládat při ukládání pozice, a za druhé proto, že cíl může být pohyblivý. To je na chytrý algoritmus docela velký požadavek, takže po něm nebudu žádat, aby našel nejkratší cestu. Přesto by však za předpokladu, že se cíl nebude hýbat, měl k cíli někdy dorazit, tedy neměl by se zacyklit. K tomu si ještě na mapě zavedu měření vzdáleností pomocí max metriky. Vzdálenost mezi dvěma body změřím funkcí vzdalenost. Tato funkce nejprve dostane souřadnice jednoho bodu, pak druhého a vrátí jejich vzdálenost.
void auto_random(): 75, 159, 204, 225
void primosmer(): 75, 80, 228
75
int vzdalenost(): 65, 76–78
21 Modul autopost
Program kraluk autopost.c
62: int vzdalenost (int x1, int y1, int x2, int y2) 63: { 64: int vzd1, vzd2; 65: 66: vzd1 = abs(x1-x2); 67: vzd2 = abs(y1-y2); 68: if(vzd1 > vzd2) return vzd1; 69: return vzd2; 70: }
Funkce post_vzdal změří vzdálenost mezi dvěmi postavami. autopost.c 72: int post_vzdal (kq_postava *p1, kq_postava *p2) 73: { 74: return vzdalenost(p1->x, p1->y, p2->x, p2->y); 75: }
Nyní se vrátím k dumání nad chytrým algoritmem. V případě, že může postava jít přímo za cílem, mohla by jít přímo za cílem. Co však dělat, když jí překáží zeď? V takovém případě chytrý algoritmus zeď obejde tak, aby byl co nejblíže svému cíli. Zeď se však dá většinou obejít dvěma směry, takže si chytrý algoritmus ještě musí vybrat tu kratší cestu. Problém nyní nastane v případě, že v okamžiku, kdy obchází zeď, ho napadne, že by se mohl zdi pustit a jít přímým směrem, ačkoliv není ještě nejblíže svému cíli. Tento problém vyřeším tak, že mu zabráním se odlepit od zdi dokud není nejblíže svému cíli u zdi. Tím bych měl chytrý algoritmus popsaný, takže přistoupím k názorné ukázce. Postava začíná na fialovém čtverečku a snaží se dostat do zeleného. Černé čtverečky jsou zdi a světle modrá čára je cesta, kterou půjde.
Nejprve jde chytrý algoritmus přímo za svým cílem. Potom narazí na zeď a obchází ji, dokud není jeho vzdálenost od cíle nejmenší (v našem příkladě 11). Zde je využita jeho lepivost ke zdi. Kdyby se k ní nelepil, tak by se zacyklil uvnitř. Pak se od zdi odlepí a jde opět přímo za svým cílem. Pak se ovšem omylem nalepí na další zeď, která má ve svém místě nejbližším cíli od cíle vzdálenost 2, zatímco v místě, kde se na ní nalepil má od cíle vzdálenost 6. Algoritmus tedy obchází druhou zeď. Nedojde ovšem až k místu, kde má vzdálenost od cíle 2, protože se těsně před tím nalepí na zeď, která má v nejbližším místě od cíle vzdálenost 0. Tuto zeď pak obchází tak dlouho, dokud se neocitne v cíli. Svoji zeď algoritmus neopustí ani v okamžiku, kdy už je jeho vzdálenost od cíle 1. Pro implementaci tohoto algoritmu jsem si ještě definoval funkce uvnitrmapy, která vrátí true v případě, že zadané souřadnice nejsou mimo mapu, a funkci jezed, která vrátí true v případě, že na void post_vzdal(): 76, 226, 236 (): 77–80
uvnitrmapy /*autopost*/ (): 77–78
76
jezed /*autopost*/
21 Modul autopost
Program kraluk
zadaných souřadnicích je zeď. Tato funkce vrací true i v případě, že postava má položku zdi nastavenou na false, takže chytrý algoritmus obchází zdi i kdyby nemusel. autopost.c 59: #define uvnitrmapy(x,y) (mapa_z && x>=0 && x<mapa.sirka && y>=0 && y<mapa.vyska) 60: #define jezed(x,y) (uvnitrmapy(x,y) && mappixel(mapa, x,y)->zed)
Funkce obejdized obejde určitý blok zdí a najde nejlepší cestu, kudy jít k cíli. Parametry x a y udávají souřadnice, ze kterých vyrazí. Parametry xx a yy udávají, kterým směrem od souřadnic x,y je zeď, kterou má funkce obejít. Právě jedna z proměnných xx a yy je tedy nula. Proměnné cilx a cily udávají souřadnice cíle, ke kterému mám být co nejblíž. Do parametru vzdal uloží nejmenší vzdálenost, na kterou se mu podél zdi podařilo přiblížit a do parametru delka uloží ušlou vzdálenost k nejbližšímu místu s touto vzdáleností. Funkce obchází zeď po směru hodinových ručiček a skončí v okamžiku, kdy se opět dostane na stejné místo. V případě, že se vyplatí jít po směru, vrátí jedničku a do parametrů nejxx a nejyy zkopíruje xx a yy. Pokud se ovšem vyplatí jít proti směru, uloží do nejxx a nejyy hodnoty, kterým směrem byla zeď, když skončil. V případě, že k dosažení minimální vzdálenosti není vůbec třeba jít podél zdi, vrátí funkce nulu. autopost.c 79: static char obejdized (int x, int y, int xx, int yy, 80: int cilx, int cily, int *vzdal, int *delka, 81: int *nejxx, int *nejyy) 82: { 83: int i; 84: int usl, vzd, prvcil, poscil; 85: int startx, starty, nxx, nyy; 86: 87: startx = x; 88: starty = y; 89: *nejxx = xx; 90: *nejyy = yy; 91: usl = 0; 92: prvcil = poscil = 0; 93: vzd = vzdalenost(x, y, cilx, cily); 94: 95: for(;;){ 96: if(jezed(x + (xx+yy), y + (yy-xx)) && 97: jezed(x + (yy), y + (-xx))){ 98: i = -xx; 99: xx = yy; 100: yy = i; 101: if(!usl) break; 102: } 103: else{ 104: if(jezed(x + (xx+yy), y + (yy-xx))){ 105: x += yy; 106: y += -xx; 107: } 108: else{ 109: x += xx+yy; 110: y += yy-xx; 111: i = xx; 112: xx = -yy; 113: yy = i; 114: } 115: usl++; 116: if((x == startx && y == starty) || !uvnitrmapy(x,y)) break; 117: i = vzdalenost(x, y, cilx, cily); 118: if(i < vzd){ 119: vzd = i; 120: prvcil = poscil = usl; 121: } 122: else if(i == vzd){ 123: poscil = usl; 124: } 125: } char obejdized /*autopost*/ (): 77, 79–80
77
21 Modul autopost 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193:
Program kraluk
} if(uvnitrmapy(x,y)){ *vzdal = vzd; if(prvcil == 0){ *delka = 0; return 0; } else if(prvcil <= usl-poscil){ *delka = prvcil; return 1; } else{ *delka = usl-poscil; *nejxx = xx; *nejyy = yy; return -1; } } x = startx; y = starty; nxx = xx = *nejxx; nyy = yy = *nejyy; usl = 0; poscil = prvcil; startx = vzd; for(;;){ if(jezed(x + (xx-yy), y + (yy+xx)) && jezed(x + (-yy), y + (xx))){ i = xx; xx = -yy; yy = i; nxx = xx; nyy = yy; vzd = startx; prvcil = poscil; usl = 0; } else{ if(jezed(x + (xx-yy), y + (yy+xx))){ x += -yy; y += xx; } else{ x += xx-yy; y += yy+xx; i = -xx; xx = yy; yy = i; } usl++; if(!uvnitrmapy(x,y)) break; i = vzdalenost(x, y, cilx, cily); if(i < vzd || (i == vzd && prvcil > usl)){ vzd = i; prvcil = -usl; } } } *vzdal = vzd; if(prvcil == 0){ *delka = 0; return 0; } else if(prvcil > 0){
78
21 Modul autopost
Program kraluk
194: *delka = prvcil; 195: return 1; 196: } 197: else{ 198: *delka = -prvcil; 199: *nejxx = nxx; 200: *nejyy = nyy; 201: return -1; 202: } 203: }
Konečně funkce auto_clever nastaví postavě směr podle chytrého algoritmu. Nejdřív prohlédne sousední čtyři políčka a jestli nezjistí, že by měl obcházet zeď, jde přímo. Pokud tímto přímým směrem opět narazí na zeď, obejde ještě tuto zeď. autopost.c 205: void auto_clever (kq_postava *post) 206: { 207: int i, ohide; 208: int cilx, cily; 209: int xx, yy, nxx, nyy, vzd, delka, smer; 210: int nejvzd, nejdelka, nejxx, nejyy, nejsmer; 211: 212: if(post->submap){ 213: ohide = post->submap->hide; 214: hidesubmap(post->submap); 215: } 216: 217: if(jezed(post->x, post->y)){ 218: if(post->submap && !ohide) unhidesubmap(post->submap); 219: post->x = post->y = 0; 220: return; 221: } 222: 223: getchytsour(post, &cilx, &cily); 224: xx = 0; yy = 1; 225: nejvzd = -1; 226: nejsmer = 0; 227: do{ 228: if(jezed(post->x + xx, post->y + yy)){ 229: smer = obejdized(post->x, post->y, xx, yy, cilx, cily, 230: &vzd, &delka, &nxx, &nyy); 231: if(nejvzd < 0 || vzd < nejvzd || (vzd == nejvzd && delka < nejdelka)){ 232: nejvzd = vzd; 233: nejdelka = delka; 234: nejxx = nxx; 235: nejyy = nyy; 236: nejsmer = smer; 237: } 238: } 239: i = xx; 240: xx = -yy; 241: yy = i; 242: } while(xx != 0 || yy != 1); 243: 244: if(nejsmer){ 245: if(!jezed(post->x + nejxx+nejsmer*nejyy, post->y + nejyy-nejsmer*nejxx)){ 246: post->xx = nejxx+nejsmer*nejyy; 247: post->yy = nejyy-nejsmer*nejxx; 248: } 249: else{ 250: post->xx = nejsmer*nejyy; 251: post->yy = -nejsmer*nejxx; 252: } 253: if(post->submap && !ohide) unhidesubmap(post->submap); 254: return; void auto_clever(): 79, 159, 204, 215, 226, 230
79
22 Modul input 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: }
Program kraluk
} primosmer(&post->xx, &post->yy, cilx-post->x, cily-post->y); if(jezed(post->x+post->xx, post->y+post->yy) && post->xx && post->yy){ xx = (post->xx-post->yy)/2; yy = (post->xx+post->yy)/2; if(jezed(post->x+xx, post->y+yy)){ if(post->submap && !ohide) unhidesubmap(post->submap); post->xx = post->yy = 0; return; } smer = obejdized(post->x+xx, post->y+yy, yy, -xx, cilx, cily, &vzd, &delka, &nxx, &nyy); if(smer <= 0){ post->xx = xx; post->yy = yy; } else{ post->xx = yy; post->yy = -xx; } } if(post->submap && !ohide) unhidesubmap(post->submap);
22 Modul input 22.1
Dešifrování inputu
Tento modul řeší převod stringu, který hráč napíše, na určitou funkci s určitými parametry. Tato určitá funkce pak provede význam napsané věty. Tuto konverzi provede funkce provedstr input.c 769: char provedstr(char *str) 770: { 771: char vysledek; 772: kq_list *l; 773: struct slovo **slova; 774: 775: l = rozeberstr(str, &popwarneznam); 776: if(!l){ 777: smazlist(&l); 778: return 0; 779: } 780: expandvetu(&l); 781: slova = (struct slovo **)LdoPA(l); 782: 783: vysledek = provedvetu(slova); 784: free(slova); 785: return vysledek; 786: }
Nejprve je string přeměněn na kq_list ukazatelů na strukturu slovo funkcí rozeberstr. input.h 29: struct slovo{ 30: int pocet; 31: char makro; 32: union{ 33: kq_list *nahradit; 34: struct veta *vety; 35: } u; 36: kq_word *ulozeno; 37: int *kateg; 38: };
void provedstr(): 80, 112
struct slovo: 80, 82–83, 90–91, 94–95, 103, 105–106
80
22 Modul input
Program kraluk
Položka počet udává, kolikrát je slovo uloženo v hashi, tedy kolik různých názvů může mít. Tento údaj je využit při uvolňování slov z paměti. Dále je zde položka makro, která, pokud je true, znamená, že slovo je makrem. Takové slovo je expandováno na seznam jiných slov, které makrem nejsou. S tím souvisí položka u. Když je slovo makrem, tak je využita její podpoložka nahradit, která obsahuje list slov, na které má být slovo expandováno. V opačném případě je využita podpoložka věty. V položce ulozeno je odkaz na kq_word, kde jsou údaje o slově pro funkci, která se nakonec spustí. Tato položka také může být NULL. V takovém případě by se slovo do této funkce nemělo dostat. V položce kateg je pole kategorií, pod které toto slovo spadá, což určuje, do kterých vět se slovo hodí a do kterých ne. Funkce rozeberstr dostane string a funkci, kterou má zavolat, když nějaké slovo nepochopí. Nejprve si string zduplikuje a aplikuje na něj funkci upravstring, čímž zajistí, že v textu nebudou přebytečné mezery, velká písmena a další podivné znaky. Pak si přečte slovo až po první mezeru a vyhledá ho v hashi pod dvěma typy. Zjistí jednak, zda jde o slovo (typ WORD) a také, zda jde o část slova (typ WORDPART). Pokud zjistí, že to je část slova, zkusí do tohoto slova přidat další úsek textu po další mezeru. Jakmile to část slova není nebo narazí na konec stringu, sebere ze stringu poslední nalezené slovo a do listu přidá pointer z nálezu tohoto slova v hashi. input.c 622: kq_list *rozeberstr (char *str, void (*neznam)()) 623: { 624: char *pomstr, ch; 625: int i,j,k; 626: kq_pin *p, *pp; 627: kq_list *vysledek; 628: 629: pomstr = dupstr(str); 630: upravstring(pomstr); 631: 632: if(!pomstr[0]){ 633: free(pomstr); 634: return NULL; 635: } 636: 637: p = NULL; 638: vysledek = NULL; 639: 640: for(i=j=0;; i++) 641: if(pomstr[i] == ’ ’ || pomstr[i] == 0){ 642: ch = pomstr[i]; 643: pomstr[i] = 0; 644: 645: if((pp = hash_find(WORD, &pomstr[j]))) k = i; 646: if(pp) p = pp; 647: 648: if(!hash_find(WORDPART, &pomstr[j]) || str[i] == 0){ 649: if(!p){ 650: neznam(&pomstr[j]); 651: smazlist(&vysledek); 652: free(pomstr); 653: return NULL; 654: } 655: if(p->typ != PINPOINTER) warning("rozeberstr: slovo v hashi neni ukazatel"); 656: 657: pomstr[i] = ch; 658: 659: addPdoL(p->u.p, &vysledek); 660: 661: p = NULL; 662: if(k == i && ch == 0) break; 663: i=j=k+1; 664: } 665: else pomstr[i] = ch; kq_list *rozeberstr(): 80–81, 92, 95
81
22 Modul input
Program kraluk
666: } 667: 668: free(pomstr); 669: return vysledek; 670: }
Na tento list je pak aplikována funkce expandvetu, která všechna slova, která jsou makrem, nahradí skupinou slov v položce u.nahradit. input.c 674: void expandvetu (kq_list **v) 675: { 676: kq_list *pom, *pomo; 677: 678: while(*v){ 679: if(((struct slovo *)((*v)->u.p))->makro){ 680: pom = ((struct slovo *)((*v)->u.p))->u.nahradit; 681: if(pom){ 682: (*v)->u.p = pom->u.p; 683: 684: for(pom = pom->next; pom; pom = pom->next){ 685: pomo = (kq_list *)mymalloc(sizeof(kq_list)); 686: pomo->u.p = pom->u.p; 687: pomo->next = (*v)->next; 688: (*v)->next = pomo; 689: v = &(*v)->next; 690: } 691: } 692: else{ 693: pomo = *v; 694: *v = pomo->next; 695: free(pomo); 696: } 697: } 698: else v = &(*v)->next; 699: } 700: }
Nakonec je list převeden na pole, na které se zavolá funkce provedvetu. Tato funkce nejprve zkontroluje, zda se ve větě nenachází slovo mimo kontext. To je takové slovo, ve kterém ulozeno->kontext <= 0. Potom hledá větu, která je kompatibilní s polem, které dostala. Větu zastupuje ukazatel na veta, tato struktura vypadá následovně: input.h 20: struct veta{ 21: void (*funkce)(int, kq_word **); 22: int pocetclenu, pocetparam; 23: struct vetnyclen *cleny; 24: struct veta *next; 25: } *jenkat;
Aby bylo možno mezi větami vyhledávat, jsou řazeny do seznamů, kde jsou propojeny přes položky next. Dále je zde pole cleny, jeho délku udává položka pocetclenu a struktura vetnyclen vypadá následovně: input.h 9: struct vetnyclen{ 10: char jekat; 11: union{ 12: struct slovo *presneslovo; 13: int *kateg; 14: } u; 15: int mistoparam; 16: };
void expandvetu(): 80, 82, 92 void provedvetu(): 80, 83 struct vetnyclen: 82, 95–96, 105
82
struct veta: 80, 82–83, 95–96, 105, 107
22 Modul input
Program kraluk
Pokud jekat == 0, musí být na daném místě slovo stejné jako v položce u.presneslovo. Pokud jekat != 0, musí být mezi polem u.kateg a polem kategorií ve slově na onom místě neprázdný průnik. Pole u.kateg je ukončeno nulou. Abych při vyhledávání správné věty nemusel prohledat všechny, mám seznamy vět roztříděné podle prvního větného členu určeného přesným slovem. Vždy při vytvoření věty je tedy vyhledán první takový větný člen a pak je věta přidána do seznamu v položce u.vety toho slova. Pokud nemá věta žádný větný člen, kde jekat != 0, je přidána do globálního seznamu vět jenkat. input.c 75: struct veta *jenkat = NULL;
Při hledání věty jsou nejprve prohledány věty prvního slova, pak věty druhého slova, . . ., až věty posledního slova a nakonec je prohledán seznam jenkat. Poté, co je věta nalezena, je třeba si připravit pole parametrů. Vytvoří se pole pointerů na kq_word tak veliké, jak udává položka pocetparam dané věty a celé se pronuluje. Pak se prochází větné členy a každý větný člen, jehož mistoparam je nezáporný, udává index do toho pole, kam se má daný větný člen nahrát. Konkrétně se tam zkopíruje položka ulozeno příslušného slova. Nakonec je spuštěna funkce nalezené věty s dvěma parametry. První je délka pole neboli pocetparam a druhý je to pole. input.c 704: char provedvetu (struct slovo **slova) 705: { 706: int i, j, k, l, d; 707: struct veta *v; 708: kq_word **parametry; 709: 710: for(d=0; slova[d]; d++) 711: if(slova[d]->ulozeno && slova[d]->ulozeno->kontext <= 0){ 712: popupwarning("_bad context", slova[d]->ulozeno->nazev); 713: return 0; 714: } 715: 716: for(i=0;;i++){ 717: if(slova[i]){ 718: if(slova[i]->makro) warning("provedvetu: spatny typ %d. slova", i); 719: v = slova[i]->u.vety; 720: } 721: else v = jenkat; 722: 723: for(;v ; v = v->next){ 724: if(v->pocetclenu == d && (!slova[i] || 725: v->cleny[i].u.presneslovo == slova[i])){ 726: for(j=0; jcleny[j].jekat){ 728: if(!slova[j]->kateg || !v->cleny[j].u.kateg) break; 729: for(k=0; slova[j]->kateg[k]; k++){ 730: for(l=0; v->cleny[j].u.kateg[l]; l++) 731: if(v->cleny[j].u.kateg[l] == slova[j]->kateg[k]) break; 732: if(v->cleny[j].u.kateg[l] == slova[j]->kateg[k]) break; 733: } 734: if(!slova[j]->kateg[k]) break; 735: } 736: else{ 737: if(v->cleny[j].u.presneslovo != slova[j]) break; 738: } 739: } 740: if(j == d){ 741: if(v->pocetparam && v->funkce){ 742: parametry = (kq_word **)mymalloc(v->pocetparam*sizeof(kq_word *)); 743: for(j = 0; jpocetparam; j++) parametry[j] = NULL; 744: for(j = 0; jcleny[j].mistoparam >= 0){ 746: if(slova[j]->ulozeno) parametry[v->cleny[j].mistoparam] = slova[j]->ulozeno; 747: else warning("provedvetu: neulozene slovo chce do parametru %d", 748: v->cleny[j].mistoparam); 749: } struct veta *jenkat: 82–83, 95, 97, 105–107
83
22 Modul input
Program kraluk
750: } 751: else parametry = NULL; 752: 753: if(v->funkce) v->funkce(v->pocetparam, parametry); 754: if(parametry) free(parametry); 755: 756: return 1; 757: } 758: } 759: } 760: if(!slova[i]){ 761: popup_info("_unknown sentence"); 762: return 0; 763: } 764: } 765: }
22.2
Syntaxe jazyka inputu
Výše zmíněné datové struktury se musí nějakým způsobem naplnit. Část informací je načteno ze souboru, takže je možné změnou načítaného souboru změnit jazyk, kterým budeme s panáčkem hovořit. V souboru jsou ignorovány znaky, které nejsou v sekci slov ani vět. Tyto sekce se mohou opakovat. Sekce slov začíná stringem words{ na začátku řádku a končí zavírací svorkatou závorkou. Sekce vět začíná stringem sentences{ na začátku řádku a končí také zavírací závorkou. Při čtení souboru může program narazit na backshlash nebo procento. Procento zruší veškerý text (včetně backshlashů a zavíracích závorek) až po konec řádku, ale ponechá enter. Backshlash se používá pro zamaskování enteru, čili \ henter i se proměni v mezeru. Dvojice \\ se promění v jeden backshlash. Pokud je za backshlashem procento, tak se nejprve aplikuje procento, které po sobě zanechá enter, ten je pak backshlashem proměněn v mezeru. Ve všech ostatních případech backshlash jen zmizí sám a také mezery, co jsou za ním. Každé slovo i každá věta odpovídá jednomu neprázdnému řádku v sekci slov nebo vět. Nejjednodušší deklarace věty je přímo napsaná věta. Věty mají ovšem takové omezení, že nemohou mít míce než 26 členů, tedy slov. Každé slovo z této věty musí být dříve deklarováno v části slov. Více mezer se proměni v jednu mezeru a mezery na krajích řádku jsou ignorovány. Za mezeru je považován i jiný znak, který není písmeno a není jinak zpracován. Nejjednodušší příklad takového souboru tedy vypadá takto: words{ jdi } sentences{ jdi } V restartující funkci by pak měla být zavolána funkce add_sent s parametrem pointer na funkci, která se má při zavolání té věty provést. Pokud bude v souboru více vět, měl by být ve zdrojáku stejný počet volání funkce add_sent a jednotlivé funkce budou pak přiřazeny řádkům vět ve stejném pořadí. Tím propojíme texty v souboru s konkrétními funkcemi ve zdrojovém kódu programu. Na řádku v sekci vět může být středník, který jakoby založí nový řádek věty, ale pro funkci add_sent se tváří stále jako jeden řádek, tedy všem větám odděleným středníkem je přiřazena stejná funkce. Podobně se dají středníkem oddělovat slova. Jaký je rozdíl mezi slovy oddělenými středníkem a oddělenými enterem vysvětlím později. Zatím rozdíl není žádný. words{ jdi; zastav; se; stůj; } sentences{ jdi zastav se; stůj } Ve zdrojáku by pak mělo být něco jako: 84
22 Modul input
Program kraluk
add_sent(&chod); // propoji se s prvnim radkem v "sentences" add_sent(&stuj); // propoji se s druhym radkem v "sentences" Slova jednoho významu mohou mít více způsobů, jak je napsat (synonyma). Synonyma se vytvoří tak, že se na řádku (středník také odděluje řádky) slova oddělí čárkami. Tím se první slovo stane původním slovem a ostatní v tomto řádku synonymy, která se v něj promění. Čárky se dají uzavřít do kulatých závorek. Tím se okolí závorek zkopíruje a ze vnitřku se vždy vybere jedna možnost. Například velký (pán, člověk, muž) expanduje na velký pán, velký člověk, velký muž Mezery jsou odstraňovány až po expanzi, takže není třeba řešit například dvě mezery mezi velký a člověk. Pokud ovšem napíšete papír(ek, eček) neexpanduje to na papírek a papíreček, ale na papírek, papír eček Místo kulatých závorek se také dají použít závorky hranaté, které označují nepoviný text. Mají tedy stejný význam jako když by na začátku kulatých závorek byla čárka. Závorky mohou být i vnořené. Další příklad: řádky [toho] (pána, člověka, muže) shrek, [[hráškově, příšerně] zelený] [zl]obr expandují na pána, člověka, muže, toho pána, toho člověka, toho muže shrek, obr, zlobr, zelený obr, zelený zlobr, hráškově zelený obr, \ hráškově zelený zlobr, příšerně zelený obr, příšerně zelený zlobr Po expanzi se mohou objevit prázdná slova, která neobsahují žádné písmeno. Taková jsou jednoduše ignorována. Není však radno, aby po expanzi zůstal celý řádek prázdný. Když je na řádku slova rovnítko, tak se deklarované slovo stane makroslovem, které se nahradí slovy, co jsou za rovnítkem. Tato slova už musí být deklarovaná a pokud zde jsou makroslova, jsou expandována. Nemůže se tedy stát, aby bylo makroslovo uvnitř makroslova. Je dobré definovat vatu (tj. výplňková slova bez významu) jako makroslovo, které expanduje na nic. Dále jsem zjistil, že se makroslovo hodí pro slovo prozkoumej, které expanduje na dvě slova: koukni a na. Vrátíme se zpět k deklaraci věty. Pokud je na řádku s větou čárka, za ní jsou napsány varianty, jak mohou být uspořádány slova této věty pomocí písmenek. Prvnímu slovu je přiřazeno písmeno a, druhému písmeno b, třetímu c, . . . Jsou-li ve větě makroslova, je písmeno přiřazené celému makroslovu a expanze proběhne až později. Jednotlivá uspořádání jsou oddělena čárkami a jsou v nich ignorovány mezery. Jiné znaky by se tam neměly vyskytovat. Když už jsou ve větě takováto pořadí, není platné původní pořadí. Nemusí být použita všechna písmenka a některá se mohou opakovat. Z toho plyne omezení, že věta nemůže mít víc než 26 členů. Toto omezení platí i když členy nejsou vyjádřeny písmeny. Příklad: words{ ukonči; program; v klidu } \sentences{ program v klidu ukonči, bca, cba, acb, ca } Funguje stejně jako kdyby v sekci vět bylo napsáno:
85
22 Modul input
Program kraluk
v klidu ukonči program; ukonči v klidu program;\ program ukonči v klidu; ukonči program Slovům je možné přidělit kategorie tak, že se před slovo napíše seznam kategorií oddělených čárkami do špičatých závorek. Každá kategorie je určena nějakým stringem. Velikost písmen zde ovšem nehraje roli, znak, který není písmenem, je považován za mezeru a počet mezer u sebe nehraje roli, tedy je na název kategorií aplikován upravstring. Kategorie napsané na začátku jsou stejné pro všechna slova na onom řádku. Středník se zde stále chová jako oddělovač řádku, ovšem není možné kategorie jakkoli zaplést do expanze. Ve větách je pak možno psát stejným způsobem místo větného členu seznam kategorií. Příklad: words{ otevři; seber; dej; na; prozkoumej <predm> sluchátko truhlu poklop <predm, misto> desku } sentences{ prozkoumej <misto, predm> otevři seber <predm> dej <predm> na <misto> } Pak program uzná následující věty: prozkoumej sluchátko prozkoumej truhlu prozkoumej poklop prozkoumej desku otevři truhlu
otevři poklop seber sluchátko seber truhlu seber desku dej sluchátko na poklop
dej dej dej dej dej
truhlu na poklop desku na poklop sluchátko na desku truhlu na desku desku na desku
Špičaté závorky však mají v tomto okamžiku ještě jednu vlastnost. Kromě určování kategorií totiž zařídí uložení tohoto slova. To znamená, že ve stejném pořadí, v jakém jsou v souboru takováto slova, by mělo být ve zdrojáku použita funkce add_word. Tato funkce vrátí ukazatel na kq_word, přičemž dostane kontext, který se tam dosadí. Ve zdrojáku by tedy mělo být něco jako: kq_word *sluchatko, truhla, poklop, deska; sluchatko = add_word(0); truhla = add_word(0); poklop = add_word(0); deska = add_word(0); add_sent(&chod); add_sent(&stuj); Tato struktura kq_word vypadá následovně: input.h 42: struct kq_word{ 43: kq_pin informace; 44: char typ; 45: int Cislo; 46: 47: int kontext, loaded_kontext; 48: char *nazev; 49: kq_word *next; kq_word: 7, 80–83, 86–88, 90, 98–99, 101, 103–108, 137, 139, 146, 149, 161, 170–173, 181–182, 185, 205–217, 240–241
86
22 Modul input
Program kraluk
50: }; 51: 52: kq_word *prvulslovo, *aktulslovo; 53: int pocet_word;
Podstatné zde jsou položky kontext, informace a info2. Do položky informace je možné si uložit libovolný údaj o slově. Při vytvoření je zde pinnull. Položka typ dává další možnosti mít o slově určitou představu. Existují zatím tři hodnoty, které jsou do této položky dosazovány: input.h 3: #define OBJWORD -2 4: #define LANGWORD -1 5: #define STDWORD 0
STDWORD je zde dosazen automaticky při vytvoření slova. LANGWORD znamená, že se jedná o slovo, které přepíná do jiného jazyka, například slovo english přepne hru do angličtiny. OBJWORD znamená, že je to slovo příslušející určitému předmětu (kq_predmet). Položku typ ani informace není vhodné měnit v průběhu hry, protože nejsou ukládány. Položka kontext oproti tomu ukládána je. Kromě toho, že se v této položce dá uchovávat informace, slouží ještě k jednomu účelu. Totiž ono slovo se dá použít jen v případě, kdy kontext > 0. V opačném případě program spustí funkci popup_warning s parametry "_bad context" a položkou nazev příslušného slova. Do položky nazev je nahrán první string, pod kterým program slovo uloží. To je takové, kde je ve všech seznamech oddělených čárkami vybrána první položka a hranaté závorky jsou ignorovány. Položka next spolu s proměnnými prvulslovo a aktulslovo řadí tato slova do fronty. Položky Cislo a loaded_kontext jsou využívány moduly save a load. Nyní se dostávám k užitečnosti středníku v sekci slov. Všem slovům odděleným středníkem na jednom řádku se totiž přiřadí stejné slovo do položky ulozeno. To, zda se slova na daném řádku vůbec uloží či nikoliv rozhoduje jen totální začátek řádku. Pokud tedy nechcete, aby slovo bylo uloženo a přitom chcete, aby mělo přiřazené kategorie, je možné napsat: words{ otevři; seber; dej; na; prozkoumej ;<predm> sluchátko ; truhlu ; poklop ;<predm, misto> desku } Pokud je žádoucí, aby slovo bylo uloženo, a přitom nemělo žádné kategorie, je možné před něj napsat jen prázdné špičaté závorky. Stejně jako v sekci slov mají špičaté závorky jako vedlejší efekt uložení daného slova, mají v sekci vět podobný vedlejší efekt. Totiž členy určené špičatými závorkami jsou předány funkci dané věty. Konkrétně je vytvořeno pole, které má tolik prvků, kolik má věta předávaných členů. Do tohoto pole se pak členy popořadě ukládají. Nakonec jsou funkci předány dva parametry, první je délka pole a druhý je pole samotné. V případě, že jsou za větou napsána pořadí podle počátečních písmenek abecedy, je pořadí v poli parametrů stále stejné. Stejně tak pole parametrů nemění velikost a v případě, že v pořadí chybí některý parametr, je na jeho místě v poli NULL. Nedoporučuje se však parametry opakovat. Může se stát, že je žádoucí, aby bylo uloženo samotné slovo nebo aby kategorie nebyly uloženy. To se dá zařídit dalšími typy závorek. Kulaté závorky označují úsek, který je ukládán. Hranaté závorky mají stejný význam jako špičaté, ale ukládány nejsou. Tedy ([kateg]) má zde stejný význam jako . 22.3
Interpretace načítání inputu
Před tím, než je čten soubor, jsou volány funkce add_word a add_sent. Tyto funkce si zařadí větu nebo slovo do fronty. Tyto funkce jsou volány při každém restartu, aby byl slovům opět nastaven počáteční kontext a především kvůli správnému propojení s předměty. To, zda tyto funkce spouštím poprvé nebo při restartu poznám podle toho, zda je win nulové. Slova jsou jednoduše řazena do fronty, kde prvním STDWORD: 87–88 LANGWORD: 87, 103–104, 107 OBJWORD: 87, 182, 185 182, 187, 205 void add_sent(): 84, 88, 187, 205–206
87
kq_word *add_word(): 86, 88,
22 Modul input
Program kraluk
prvkem je prvulslovo a posledním prvkem je aktulslovo. Do proměnné pocet_word ukládám počet slov v této frontě. Při druhém průchodu už tuto frontu jen procházím proměnnou aktulslovo. input.c 27: kq_word *prvulslovo = NULL; 28: kq_word *aktulslovo = NULL; 29: int pocet_word = 0; input.c 38: kq_word *add_word (char kontext) 39: { 40: kq_word *vysledek; 41: 42: if(win){ 43: vysledek = aktulslovo; 44: aktulslovo = aktulslovo->next; 45: } 46: else{ 47: vysledek = (kq_word *)mymalloc(sizeof(kq_word)); 48: vysledek->next = NULL; 49: if(!prvulslovo) aktulslovo = prvulslovo = vysledek; 50: else aktulslovo->next = vysledek; 51: aktulslovo = vysledek; 52: vysledek->Cislo = ++pocet_word; 53: vysledek->nazev = NULL; 54: vysledek->informace = pinnull; 55: vysledek->typ = STDWORD; 56: } 57: vysledek->kontext = kontext; 58: 59: return vysledek; 60: }
Ukazatele na funkce vět řadím do zásobníku kq_list. Při startu hry je nakonec tento zásobník zkonvertován na pole funkcí finishws. Délka toho pole je v proměnné dfv. Při restartu nemá funkce add_sent žádný efekt. input.c 31: static kq_list *lsents = NULL; 32: static void (**funkvety)(int, kq_word **); 33: static int dfv = 0; input.c 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73:
void add_sent (void (*f)(int, kq_word **)) { if(win) return; addPdoL(f, &lsents); dfv++; } void finishws () { funkvety = (void (**)(int, kq_word **))LdoPA(lsents); smazlist(&lsents); }
Pak spustím funkci nactiinput. Tato funkce dostane název jazyka a otevře příslušný soubor. Dále nastaví pps a pfv na nulu. Tyto proměnné jsou zkratkami od Počet Proměnných Slov a Počet Funkcí Vět. Proměnnou pps jsou počítána přečtená uložená slova (tedy ta se skobatou závorkou na začátku řádku) a proměnnou pfv jsou počítány přečtené věty. Na konci by se mělo shodovat pps s pocet_word a pfv s dfv Pokud to neplatí, program vypíše warning. Z tohoto souboru čte jednotlivé znaky. Pomocí lokálních proměnných w a s kontroluje shodu čtených znaků se stringy startword a startsent. kq_word *prvulslovo: 87–89, 103, 139, 147, 149–150, 188 kq_word *aktulslovo: 87–89, 91, 188 kq_word *pocet_word: 87–89, 91, 137, 150 void finishws(): 88, 188 int dfv /*input*/ : 88–89, 96 void nactiinput(): 89, 105–106 int pps /*input*/ : 88–89, 91 int pfv /*input*/ : 88–89, 96–97 char *startword: 89 char *startsent: 89
88
22 Modul input
Program kraluk input.c
17: char startword[] = "words{"; 18: char startsent[] = "sentences{";
Jakmile shodu s jedním ze stringů nalezne, spustí funkci ctiradky. input.c 144: void nactiinput (char *jazyk) 145: { 146: char *fullname; 147: FILE *f; 148: int ch, w, s; 149: 150: fullname = joinstrings(DATADIR, LANGDIR, jazyk, INPUTSUFFIX, NULL); 151: if((f = fopen (fullname, "r")) == NULL){ 152: warning("Nepovedlo se otevrit soubor %s", fullname); 153: free(fullname); 154: return; 155: } 156: 157: pps = pfv = 0; 158: aktulslovo = prvulslovo; 159: 160: w=s=0; 161: 162: poslkat = 2; 163: 164: for(;;){ 165: ch = fgetc(f); 166: if(ch == EOF) break; 167: else if(ch == ’\n’) w=s=0; 168: else{ 169: if(w >= 0 && ch == startword[w]){ 170: w++; 171: if(!startword[w]){ 172: w = -1; 173: s = -1; 174: ctiradky(f, &ulozslova); 175: } 176: } 177: else w = -1; 178: 179: if(s >= 0 && ch == startsent[s]){ 180: s++; 181: if(!startsent[s]){ 182: w = -1; 183: s = -1; 184: ctiradky(f, ulozvetu); 185: } 186: } 187: else s = -1; 188: } 189: } 190: 191: if(pps != pocet_word) warning("spatny pocet slov, zrojak: %d, soubor: %d", pocet_word, pps); 192: if(pfv != dfv) warning("spatny pocet vet, zrojak: %d, soubor: %d", dfv, pfv); 193: 194: free(fullname); 195: fclose(f); 196: }
Funkce ctiradky načte do stringu vždy celý řádek, přičemž za oddělovač řádku považuje i středník. Prázdné řádky (více enterů za sebou) ignoruje. Jakožto parametr dostane soubor, který má číst a také funkci, kterou má na každý řádek pustit. Této předá tři parametry. První je onen string, druhý je údaj, zda je tento string na začátku řádku (není před ním středník), a třetí je údaj, zda je tento string na konci řádku (není za ním středník). Funkce ctiradky se ukončí v okamžiku, kdy narazí na zavírací svorkatou závorku. void ctiradky /*input*/ (): 89–90, 95
89
22 Modul input
Program kraluk input.c
103: static void ctiradky (FILE *f, void (*zpracujradek)(char *, char zacr, char konr)) 104: { 105: char *str, ch, zacr, konr; 106: kq_string radek; 107: 108: zacr = 1; 109: initstr(&radek); 110: for(;;){ 111: while((ch=ctiznak(f,1)) == ’\n’ || ch == ’ ’ || ch == ’\t’); 112: if(ch == EOF || ch == ’}’){ 113: if(ch == EOF) warning("predcasny konec souboru"); 114: return; 115: } 116: for(;;){ 117: if(ch == ’\n’ || ch == EOF || ch == ’}’ || ch == ’;’){ 118: str = zestringuj(&radek); 119: if(ch == ’;’) konr = 0; 120: else konr = 1; 121: 122: zpracujradek(str, zacr, konr); 123: 124: smazstr(&radek); 125: free(str); 126: if(ch == ’;’) zacr = 0; 127: else zacr = 1; 128: 129: if(ch == EOF || ch == ’}’){ 130: if(ch == EOF) warning("predcasny konec souboru"); 131: return; 132: } 133: if(ch != ’;’) break; 134: } 135: else zapisznak(ch, &radek); 136: 137: ch=ctiznak(f,1); 138: } 139: } 140: }
Při čtení řádku využívá funkci ctiznak místo standardního fgetc. Tato funkce zařizuje možnost komentářů a rušení backshlashů. V parametru je údaj, zda má být backshash aktivní. input.c 88: static int ctiznak (FILE *f, int backslash) 89: { 90: char ch; 91: 92: ch=fgetc(f); 93: if(backslash && ch == ’\\’){ 94: while((ch = ctiznak(f, 0)) == ’ ’ || ch == ’\t’); 95: if(ch == ’\n’) return ’ ’; 96: } 97: else if(ch == ’%’){ 98: while((ch = fgetc(f)) != ’\n’ && ch != EOF); 99: } 100: return ch; 101: }
Pro předání funkci ctiradky jsou zde připraveny dvě funkce. První je ulozslova. input.c 342: static kq_word *tus; 343: 344: static void ulozslova (char *str, char zacr, char konr) 345: { 346: char **slova; 347: struct slovo *slovo; void ctiznak /*input*/ (): 90
void ulozslova /*input*/ (): 89–90, 93
90
22 Modul input 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415:
Program kraluk
kq_list *lpompol; int *kateg; int i, j; for(i=0; str[i] == ’ ’ || str[i] == ’\t’ ; i++); if(str[i] == ’<’){ kateg = nactikat(str, &i, ’>’); if(zacr){ if(pps < pocet_word){ tus = aktulslovo; aktulslovo = aktulslovo->next; } else tus = NULL; pps++; } } else{ kateg = NULL; if(zacr) tus = NULL; } slova = seznamslov(str, 0, 0, &i); j = i; // Zalolození struktury slovo = (struct slovo *)mymalloc(sizeof(struct slovo)); slovo->ulozeno = NULL; slovo->kateg = kateg; slovo->pocet = 0; slovo->makro = 0; slovo->u.vety = NULL; slovo->ulozeno = tus; if(zacr && tus && tus->nazev){ free(tus->nazev); tus->nazev = NULL; }
// Pridani do hashe: for(i=0; slova[i]; i++){ upravstring(slova[i]); if(!slova[i][0]){ free(slova[i]); continue; } if(tus && !tus->nazev) tus->nazev = dupstr(slova[i]); slovo->pocet++; wordtohash(slovo, slova[i]); free(slova[i]); } free(slova); if(slovo->pocet == 0){ if(kateg){ warning("prazdne slovo ma kategorie"); free(kateg); } free(slovo); } if(konr && tus && !tus->nazev) warning("ukladane slovo nema nazev"); if(str[j] == ’=’){
91
22 Modul input 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: } 427: }
Program kraluk
if(!slovo){ warning("makro slovo je prazdne"); return; } if(kateg || tus) warning("makroslovo je prekombinovane"); lpompol = rozeberstr(&str[j], &warneznam); expandvetu(&lpompol); slovo->makro = 1; slovo->u.nahradit = lpompol;
Nejdříve se podívám na začátek a pokud tam je skobatá závorka načtu kategorie. Kromě toho, v případě, že jsem na začátku řádku, ještě uložím aktuální ukládané slovo do proměnné tus. Pak provedu expanzi a uložím slovo do hashe. Nakonec, pokud je na konci rovnítko, změním slovo na makroslovo. Pro načítání kategorií použiji funkci nactikat. Tato funkce kromě stringu dostane ukazatel na index tohoto stringu. Na začátku je tento index nastaven na otevírací skobaté závorce a po skončení je nastaven na znak těsně za zavírací závorkou. Posledním parametrem je znak zavírací závorky. input.c 212: static int *nactikat (char *str, int *i, char k) 213: { 214: int j; 215: int *vysledek; 216: char *pomstr; 217: kq_list *l; 218: 219: l = NULL; 220: 221: for(j = ++*i;; j++) 222: if(str[j] == ’,’ || str[j] == k || str[j] == 0){ 223: pomstr = dupnstr(&str[*i], j-*i); 224: upravstring(pomstr); 225: 226: if(pomstr[0]) addIdoL(katnumber(pomstr), &l); 227: free(pomstr); 228: 229: if(!str[j]){ 230: warning("chybi zaviraci zavorka ’%c’", k); 231: *i=j; 232: break; 233: } 234: 235: *i=j+1; 236: 237: if(str[j] == k) break; 238: } 239: 240: if(!l) return NULL; 241: 242: vysledek = LdoIA(l); 243: smazlist(&l); 244: return vysledek; 245: }
Kategorie je ze stringu převedena na přirozené číslo. Pole kategorií je zakončeno nulou. Stringům přiřazuji čísla postupně od dvojky, protože číslo 1 je rezervováno pro kategorii slov jazyků. Nejnižší číslo, kterému ještě není přiřazena kategorie, je uložené v proměnné poslkat. input.c 142: static int poslkat;
Pro konverzi ze stringu na číslo je použita funkce katnumber. Tato funkce také založí novou kategorii, pokud daný string ještě nebyl použit. kq_word *tus /*input*/ : 90–92 int *nactikat /*input*/ (): 91–92, 95 : 89, 92–93 int katnumber /*input*/ : 92–93
92
int poslkat /*input*/
22 Modul input
Program kraluk input.c
198: static int katnumber (char *katnazev) 199: { 200: kq_pin *p, p2; 201: 202: p = hash_find(WORDCAT, katnazev); 203: if(!p || p->typ != PININT){ 204: if(p) warning("kategorie ma v hashi spatny typ"); 205: p2 = pinint(poslkat++); 206: p = &p2; 207: hash_add(WORDCAT, katnazev, p); 208: } 209: return p->u.i; 210: }
Poté, co funkce ulozslova zjistí kategorie, spustí expanzi. To řeší funkce seznamslov. Tato funkce vrátí pole rozexpandovaných stringů. První parametr této funkce je string, který má být expandován a poslední (čtvrtý) je ukazatel na index do toho stringu. Na začátku ukazuje na první znak té části stringu, která má být expandována a na konci ukazuje na poslední znak (nula nebo rovnítko). Druhý a třetí parametr jsou parametry využívané při zarekurzení této funkce. Pokud tyto parametry nejsou nulou, ukazují další možnosti, kterým může expandovaný string skončit. Funkce seznamslov zvládne bez rekurze jen stringy, ve kterých se nevyskytují závorky. Funguje tak, že v proměnné s si udržuje index začátku dané verze slova a proměnnou i prochází pole dokud nenarazí na čárku nebo na konec (rovnítko nebo nula). Když narazí na čárku, uloží si slovo do seznamu l, posune si proměnnou s za čárku a pokračuje. Nakonec promění seznam l na pole. Pokud ovšem narazí na otevírací závorku, zahájí rekurzi. Potřebuje totiž rozexpandovat vnitřek závorky, a potom ještě tu část za závorkou. Spustí tedy dvakrát po sobě sama sebe a získá tak dvě pole stringů. Tato pole projde, propojí každý prvek s každým a na začátek připojí ještě část před závorkami. Při expanzi vnitřku závorek nebo části za závorkami však potřebuji, aby se funkce ukončila dříve, než když narazí na konec stringu. Předávám tedy funkci parametry, kdy má skončit. Do druhého parametru předám uzavírací závorku a do třetího čárku. input.c 247: static char **seznamslov (char *str, char k1, char k2, int *kdekon) 248: { 249: int i,j,k, s,t, delka; 250: char ch; 251: kq_list *l; 252: 253: char **s1, **s2, *vysls, **vysledek; 254: 255: l = NULL; 256: 257: if(k1 == ’]’ && k2 ==0) addPdoL(dupstr(""), &l); // hranate zavorky jsou nepovinne 258: 259: for(s=i=*kdekon;;){ 260: if(str[i] == 0 || str[i] == ’=’ || str[i] == k1 || str[i] == k2){ 261: addPdoL(dupnstr(&str[s], i-s), &l); 262: break; 263: } 264: else if(str[i] == ’]’){ 265: warning("nezparovana zavorka ’]’"); 266: i++; 267: } 268: else if(str[i] == ’)’){ 269: warning("nezparovana zavorka ’)’"); 270: i++; 271: } 272: else if(str[i] == ’[’ || str[i] == ’(’){ 273: t = i-s; 274: 275: if(str[i] == ’(’) ch = ’)’; 276: else ch = ’]’; 277: i++; char **seznamslov /*input*/ (): 91, 93–94
93
22 Modul input 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: }
Program kraluk
s1 = seznamslov(str, ch, 0, &i); i++; s2 = seznamslov(str, k1, ’,’, &i); delka = t+1; for(j=0; s1[j]; j++){ delka += strlen(s1[j]); for(k=0; s2[k]; k++){ delka += strlen(s2[k]); vysls = mymalloc(sizeof(char)*delka); strncpy(vysls, &str[s], t); strcpy(&vysls[t], s1[j]); strcpy(&vysls[t+strlen(s1[j])], s2[k]); addPdoL(vysls, &l); delka -= strlen(s2[k]); } delka -= strlen(s1[j]); } for(j=0; s1[j]; j++) free(s1[j]); for(k=0; s2[k]; k++) free(s2[k]); free(s1); free(s2); if(str[i] == k1 || str[i] == k2 || str[i] == ’=’ || str[i] == 0) break; s = ++i; } else if(str[i] == ’,’){ addPdoL(dupnstr(&str[s], i-s), &l); s = ++i; } else i++; } if((str[i] == ’=’ || str[i] == 0) && k1){ warning("Predcasne ukonceni slova (chybi uzaviraci zavorka)"); i--; } *kdekon = i; vysledek = (char **)LdoPA(l); smazlist(&l); return vysledek;
Nakonec slova ukládám do hashe funkcí wordtohash. Kromě samotného slova je totiž třeba uložit informaci o částech slova. input.c 325: void wordtohash (struct slovo *w, char *str) 326: { 327: kq_pin p; 328: int i; 329: 330: p = pinpointer(w); 331: 332: hash_add(WORD, str, &p); 333: 334: for(i=strlen(str)-1; i; i--) 335: if(str[i] == ’ ’){ 336: str[i] = 0; 337: hash_add(WORDPART, str, &pinnull); 338: str[i] = ’ ’; 339: } 340: } void wordtohash(): 91, 94, 105
94
22 Modul input
Program kraluk
Druhá funkce pro funkci ctiradky je ulozvetu. Tato funkce funguje tak, že si nejdříve přečte větné členy do pole a pak toto pole využívá při čtení možných pořadí věty. Pokud žádná pořadí zapsaná písmeny abecedy na řádku nejsou, funkce si sama vyrobí string abcd... Pro každý string funkce nejprve spočítá počet větných členů, pak namallokuje pole příslušné délky a až v druhém průchodu kopíruje větné členy z lokálního pole. Nakonec je věta přidělena ke svému prvnímu přesnému slovu nebo do seznamu jenkat. input.c 429: static void ulozvetu (char *str, char zacr, char konr) 430: { 431: int i,j,k, pocetp, pocetc, jeparam; 432: char ch; 433: struct veta *v; 434: kq_list *l; 435: struct slovo **pompol, *s; 436: int *kateg; 437: 438: struct vetnyclen vc[26]; 439: char nahrstr[28]; 440: 441: pocetp = pocetc = 0; 442: jeparam = 0; 443: 444: // definice vety: 445: 446: for(i=0;;){ 447: for(j=i; str[j] != ’<’ && str[j] != ’[’ && str[j] != ’,’ 448: && str[j] != ’(’ && str[j] != ’)’ && str[j] != 0; j++); 449: ch = str[j]; 450: str[j] = 0; 451: 452: l = rozeberstr(&str[i], &warneznam); 453: pompol = (struct slovo **)LdoPA(l); 454: smazlist(&l); 455: 456: for(k=0; pompol[k]; k++){ 457: if(pocetc < 26){ 458: vc[pocetc].jekat = 0; 459: vc[pocetc].u.presneslovo = pompol[k]; 460: if(jeparam){ 461: vc[pocetc].mistoparam = pocetp; 462: if(vc[pocetc].u.presneslovo->makro) 463: pocetp += delkaL(vc[pocetc].u.presneslovo->u.nahradit); 464: else pocetp++; 465: } 466: else vc[pocetc].mistoparam = -1; 467: } 468: pocetc++; 469: } 470: free(pompol); 471: 472: str[j] = ch; 473: 474: if(ch == 0 || ch == ’,’) break; 475: 476: if(ch == ’<’ || ch == ’[’){ 477: if(ch == ’<’) kateg = nactikat(str, &j, ’>’); 478: else kateg = nactikat(str, &j, ’]’); 479: if(pocetc < 26){ 480: vc[pocetc].jekat = 1; 481: vc[pocetc].u.kateg = kateg; 482: if(ch == ’<’ || jeparam) vc[pocetc].mistoparam = pocetp; 483: else vc[pocetc].mistoparam = -1; 484: } 485: else free(kateg); 486: pocetc++; void ulozvetu /*input*/ (): 89, 95
95
22 Modul input
Program kraluk
487: if(ch == ’<’ || jeparam) pocetp++; 488: i=j; 489: } 490: else if(ch == ’(’){ 491: if(jeparam) warning("vlozena zavorka ’(’ v definici vety"); 492: jeparam = 1; 493: i=j+1; 494: } 495: else if(ch == ’)’){ 496: if(!jeparam) warning("nezparovana zavorka ’)’ v definici vety"); 497: jeparam = 0; 498: i=j+1; 499: } 500: else warning("neco shnileho"); 501: } 502: 503: // poradi vety: 504: 505: if(!str[j]){ 506: str = nahrstr; 507: str[0] = ’,’; 508: for(j=0; j-1<pocetc && ’a’-1 + j <= ’z’; j++) str[j] = ’a’-1 + j; 509: str[j] = 0; 510: j=0; 511: } 512: 513: while(str[j]){ 514: v = (struct veta *)mymalloc(sizeof(struct veta)); 515: v->pocetclenu = 0; 516: v->pocetparam = pocetp; 517: if(pfv < dfv) v->funkce = funkvety[pfv]; 518: 519: // spocitam cleny: 520: 521: j++; 522: i=j; 523: while(str[j] && str[j] != ’,’){ 524: str[j] = tolower(str[j]); 525: if(str[j] != ’ ’){ 526: if(str[j] < ’a’ || str[j] > ’z’){ 527: warning("v urceni poradi vety je jiny znak nez pismeno anglicke abecedy"); 528: } 529: else if(str[j]-’a’ >= pocetc){ 530: warning("v urceni poradi vety je prilis vysoke pismenko"); 531: } 532: else{ 533: if(!vc[str[j]-’a’].jekat && 534: vc[str[j]-’a’].u.presneslovo->makro) 535: v->pocetclenu += delkaL(vc[str[j]-’a’].u.presneslovo->u.nahradit); 536: else v->pocetclenu++; 537: } 538: } 539: j++; 540: } 541: 542: v->cleny = (struct vetnyclen *)mymalloc((v->pocetclenu)*sizeof(struct vetnyclen)); 543: 544: // ulozim cleny: 545: 546: j=i; 547: k=0; 548: while(str[j] && str[j] != ’,’){ 549: if(str[j] >= ’a’ && str[j] <= ’z’ && str[j]-’a’ < pocetc){ 550: if(!vc[str[j]-’a’].jekat){ 551: if(vc[str[j]-’a’].u.presneslovo->makro){ 552: l = vc[str[j]-’a’].u.presneslovo->u.nahradit; 553: i = delkaL(l); 554: jeparam = vc[str[j]-’a’].mistoparam;
96
22 Modul input
Program kraluk
555: if(jeparam >= 0) jeparam += i; 556: k += i; 557: i = k; 558: while(l){ 559: k--; 560: v->cleny[k].jekat = vc[str[j]-’a’].jekat; 561: if(jeparam >= 0) 562: jeparam--; 563: v->cleny[k].mistoparam = jeparam; 564: v->cleny[k].u.presneslovo = l->u.p; 565: l = l->next; 566: } 567: k=i; 568: } 569: else{ 570: v->cleny[k].jekat = vc[str[j]-’a’].jekat; 571: v->cleny[k].mistoparam = vc[str[j]-’a’].mistoparam; 572: v->cleny[k].u.presneslovo = vc[str[j]-’a’].u.presneslovo; 573: k++; 574: } 575: } 576: else{ 577: v->cleny[k].jekat = vc[str[j]-’a’].jekat; 578: v->cleny[k].mistoparam = vc[str[j]-’a’].mistoparam; 579: if(vc[str[j]-’a’].u.kateg){ 580: for(i=0; vc[str[j]-’a’].u.kateg[i]; i++); 581: 582: v->cleny[k].u.kateg = (int *)mymalloc((i+1)*sizeof(int)); 583: 584: for(i=0; vc[str[j]-’a’].u.kateg[i]; i++) 585: v->cleny[k].u.kateg[i] = vc[str[j]-’a’].u.kateg[i]; 586: v->cleny[k].u.kateg[i] = 0; 587: } 588: else{ 589: v->cleny[k].u.kateg = NULL; 590: } 591: k++; 592: } 593: } 594: j++; 595: } 596: if(k != v->pocetclenu) 597: warning("ulozvetu: spatne spocteny pocet slov, k=%d, v->pocetclenu = %d", 598: k, v->pocetclenu); 599: 600: for(i=0; ipocetclenu && v->cleny[i].jekat; i++); 601: 602: if(i == v->pocetclenu){ 603: v->next = jenkat; 604: jenkat = v; 605: } 606: else{ 607: s = v->cleny[i].u.presneslovo; 608: if(s->makro) warning("ulozvetu: prvni slovo ma spatny typ"); 609: 610: v->next = s->u.vety; 611: s->u.vety = v; 612: } 613: } 614: for(i=0; i<pocetc; i++) 615: if(vc[i].jekat == 1) free(vc[i].u.kateg); 616: 617: if(konr) pfv++; 618: }
97
23 Modul output
Program kraluk
23 Modul output Tento modul řeší převedení labelíku ve zdrojáku na text, čímž spolu s modulem input zařizuje možnost více jazyků. V knihovně pomocných funkcí používám pouze takové labelíky, které začínají na podtržítko. Konkrétně to jsou: _restart? _help _about _empty inv
:: :: :: ::
_save :: _load :: _languages ::
Otázka, zda to hráč s restartem myslí vážně Nápověda zobrazená kliknutím myší nebo klávesou F1 Informace zobrazené při prvním spuštění nebo klávesou F10 Oznámení, že je inventář prázdný Nadpis vyskočeného okna pří ukládání pozice Nadpis vyskočeného okna pří načítání pozice Nadpis výběru jazyků
_unknown word _bad kontext _unknown sentence _unknown output
:: :: :: ::
Varování, Varování, Oznámení, Varování,
že že že že
program slovo # program program
nezná slovo # nemá kladný kontext nepochopil větu nezná output #
_same language :: oznámení, že jazyk, do kterého hráč chce přepnout, už je nastaven _return to language :: nápověda, jak se vrátit k původnímu jazyku _language start :: informace o tom, že bylo právě přepnuto do tohoto jazyka _uz mas
::
Varování, že předmět #, který chce hráč sebrat, je v inventáři
_bere :predmet: Oznámení, že hráč právě sebral předmět # _too far :: Oznámení, že je hráč příliš daleko od předmětu, který chce vzít _inv __inv _inv_look
:predmet: Název predmetu se stavem false :predmet: Název předmětu se stavem true :predmet: Povídání o předmětu se stavem false (při jeho zobrazení) __inv_look :predmet: Povídání o předmětu se stavem true (při jeho zobrazení) Pod určitým stringem může být uložen ukazatel na datový typ kq_output. output.h 1: struct kq_output{ 2: char *str; 3: char orig; 4: kq_output *next; 5: kq_word *slovo; 6: };
Hledaný string je v položce str. Položka orig je využita při mazání outputu. Díky položce next mohu tyto outputy řadit do seznamu. Poslední položka je slovo. Totiž nemusím napsat jen labelík, ale k němu mohu napsat i nějaké slovo (ukazatel na kq_word). Tato položka může být (a bývá) NULL. Funkce, která převádí string a slovo na výstupní string, je outputstring. Tato funkce vyhledá pomocí hashe a prvního parametru příslušný seznam a v něm náhodně vybere prvek, u které se shoduje položka slovo s druhým parametrem funkce outputstring. To, co funkce vrátí je string, který není radno mazat (free). Pokud není nalezen přislušný labelík s příslušným slovem, je vrácen NULL.
kq_output: 7, 98–99, 101–103, 106
char *outputstring(): 21, 98–100, 107–108, 165, 186
98
23 Modul output
Program kraluk output.c
163: char *outputstring (char *label, kq_word *slovo) 164: { 165: kq_pin *pin; 166: kq_output *pom; 167: int pocet; 168: 169: pin = hash_find(OUTPUT, label); 170: if(pin == NULL) return NULL; 171: 172: if(pin->typ != PINPOINTER){ 173: warning("spatny typ outputu"); 174: return NULL; 175: } 176: 177: pocet = 0; 178: for(pom = pin->u.p; pom; pom = pom->next) 179: if(pom->slovo == slovo) pocet++; 180: 181: if(!pocet) return NULL; 182: 183: pocet = rand()%pocet; 184: for(pom = pin->u.p; pom; pom = pom->next) 185: if(pom->slovo == slovo){ 186: if(!pocet) break; 187: pocet--; 188: } 189: 190: if(!pom){ 191: warning("spatne spocteny nahodny output"); 192: return NULL; 193: } 194: 195: return pom->str; 196: }
23.1
Vyskakovací output
Nejčastější operace se získaným stringem je jeho zobrazení pomocí funkce popupstring. To dělá funkce popupoutput. Pokud není hledaný output nalezen, vyskočí okno s varováním a vrátí nulu. Nulu vrátí i v případě, že je okno zrušeno klávesou Escape. Jinak vrátí jedničku. output.c 237: char popupoutput (char *label, kq_word *slovo, 238: float sirka, float vyska, float x, float y) 239: { 240: char *str; 241: 242: str = outputstring(label, slovo); 243: if(str) return popupstring(sirka, vyska, x, y, str, 0); 244: popupwarning("_unknown output", label); 245: return 0; 246: }
Další funkce, která situaci ještě zjednodušuje, je popup_info. Tato funkce už vyžaduje jen labelík. Rozměry a umístění okna určí z hodnot DEF_POP_SIRKA, DEF_POP_VYSKA, DEF_POP_X, DEF_POP_Y, a jako slovo zvolí NULL. output.c
248: char popup_info (char *label) 249: { 250: return popupoutput(label, NULL, DEF_POP_SIRKA, DEF_POP_VYSKA, DEF_POP_X, DEF_POP_Y); 251: }
Poslední output funkce, která vyskočí s oknem, je popupwarning. Tato funkce má podobnou funkci jako popup_info, ale kromě labelíku má ještě jeden parametr. Tento parametr je string, který se vepíše char popupoutput(): 99, 184–186, 213–214 char popup_info(): 21, 25, 84, 99, 107, 185, 188, 204, 206–216, 218, 220–226, 228, 230–232, 234, 236, 238–241 void popupwarning(): 83, 99–100, 184, 214–215
99
23 Modul output
Program kraluk
do nalezeného stringu tam, kde je znak kříž. Zde je třeba ještě řešit situaci, kdy není zanesen labelík _unknown output, protože to je labelík, který je použit v případě, že není nějaký labelík nalezen. output.c 198: void popupwarning (char *label, char *unknown) 199: { 200: char *str, *str2; 201: int i, j; 202: 203: str = outputstring(label, NULL); 204: if(!str){ 205: if(strcmp(label, "_unknown output")){ 206: popupwarning ("_unknown output", label); 207: return; 208: } 209: else str = "unknown output: #"; 210: } 211: 212: j=1; 213: for(i=0; str[i]; i++){ 214: if(str[i] == ’#’) j += strlen(unknown); 215: else j++; 216: } 217: 218: str2 = mymalloc(sizeof(char)*j); 219: 220: j=0; 221: for(i=0; str[i]; i++){ 222: if(str[i] == ’#’){ 223: strcpy(&str2[j], unknown); 224: j += strlen(unknown); 225: } 226: else{ 227: str2[j] = str[i]; 228: j++; 229: } 230: } 231: str2[j] = 0; 232: 233: popupstring(DEF_POP_SIRKA, DEF_POP_VYSKA, DEF_POP_X, DEF_POP_Y, str2, 0); 234: free(str2); 235: }
23.2
Načítání outputu
Output je podobně jako input načtítán ze souboru. Základní princip je ten, že labelík je napsán na začátku řádku a text, který je pod ním odsazený doprava, je výstupní string. Dále se lehce opičím po TEXovském token procesoru tím, že více mezer u sebe se promění v jednu a mezery na začátku a konci řádku jsou ignorovány a enter je považován za mezeru. Prázdný řádek je považován za skutečný konec řádku, ale prázdné řádky těsně před labelíkem jsou ignorovány. Při předání tohoto stringu funkci popupstring je text opět rozlámán podle velikosti okna. Tato funkce navíc z vlnky udělá nezalomitelnou mezeru, takže moduly output a popup vlastně tvoří takový skoro TEX. Pokud je na začátku souboru nějaký odsazený text, je ignorován. Nejjednoduší příklad outputu tedy vypadá takto: Co to deláš? Nečti tento soubor. labelik Vítej na scéně Tady tento text se zobrazí v~okamžiku, kdy se ve zdrojáku objeví popup_info("labelik"), přičemž text "Vítej na scéně" (ovšem pouze jeho první výskyt) bude na samostatném řádku 100
23 Modul output
Program kraluk
labelik 2 I ty kujóne, že jsi napsal popup_info("labelik 2") Takové texty mají v položce slovo NULL. Pokud tam chcete dostat nějaké slovo, napište za labelík dvojtečku a na ten samý řádek nějaké slovo z inputu. S tímto slovem musí být program obeznámen ze souboru input a navíc to slovo musí být uloženo do kq_word. Když za dvojtečkou nic není, tak je slovo NULL, stejně jako by tam dvojtečka nebyla. Za slovem se může vyskytovat další dvojtečka a pak už může pokračovat text. Řádek za dvojtečkou však není nikdy považován jako prázdný. Dále je možné přiřadit více labelíkům stejný text. To se udělá tak, že se labelíky oddělí čárkami. Labelík s dvojtečkou a slovem zde tvoří ucelený prvek, který se odděluje čárkami, takže například labelik, labelik 2: slovo: Text. je to samé jako labelik :: Text. labelik 2: slovo: Text. Dále jsou za čárkou ignorovány mezery, tabelátory a entery, takže je možné zalomit seznam labelíků na více řádků. Funkce, která tento soubor přečte, se jmenuje nactioutput. output.c 16: void nactioutput (char *jazyk) 17: { 18: char *fullname; 19: char ch; 20: char zacatekr = 1; 21: char prazdnyr = 1; 22: char mezera = 0; 23: int pocetenteru = 0; 24: int zadvojteckou = 0; 25: 26: kq_pin pin, *ppin; 27: kq_string nekos; 28: char *label; 29: kq_list *oplist = NULL; 30: kq_list *pom; 31: kq_output *op = NULL; 32: kq_output *pop; 33: 34: FILE *f; 35: 36: fullname = joinstrings(DATADIR, LANGDIR, jazyk, OUTPUTSUFFIX, NULL); 37: if((f = fopen (fullname, "r")) == NULL){ 38: warning("Nepovedlo se otevrit soubor %s", fullname); 39: free(fullname); 40: return; 41: } 42: 43: for(;;){ 44: ch = fgetc(f); 45: 46: if(zadvojteckou){ 47: while(ch == ’ ’ || ch == ’\t’) ch = fgetc(f); 48: if(ch == ’\n’) ch = fgetc(f); 49: else zacatekr = 0; 50: zadvojteckou = 0; 51: } 52: 53: if(ch == ’\n’){ 54: if(prazdnyr){ 55: pocetenteru++; void nactioutput(): 101, 105–106
101
23 Modul output 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123:
Program kraluk
mezera = 0; } else{ pocetenteru = 0; mezera = 1; } prazdnyr = 1; zacatekr = 1; } else if(ch == ’ ’ || ch == ’\t’){ if(!prazdnyr) mezera = 1; zacatekr = 0; } else if(zacatekr || ch == EOF){ if(op){ op->str = zestringuj(&nekos); for(pom = oplist; pom; pom = pom->next) ((kq_output *)(pom->u.p))->str = op->str; smazlist(&oplist); smazstr(&nekos); } else initstr(&nekos); if(ch == EOF) return; op = (kq_output *)mymalloc(sizeof(kq_output)); op->orig = 1; pop = op; for(;;){ pop->slovo = NULL; mezera = 0; while(ch != EOF && ch != ’\n’ && ch != ’:’ && ch != ’,’){ if(ch == ’ ’ || ch == ’\t’) mezera = 1; else{ if(mezera){ zapisznak(’ ’, &nekos); mezera = 0; } zapisznak(ch, &nekos); } ch = fgetc(f); } label = zestringuj(&nekos); ppin = hash_find(OUTPUT, label); if(ppin){ if(ppin->typ != PINPOINTER) warning("nactioutput: spatny typ pinu"); pop->next = ppin->u.p; ppin->u.p = pop; } else{ pin = pinpointer(pop); hash_add(OUTPUT, label, &pin); pop->next = NULL; } free(label); smazstr(&nekos); if(ch == ’:’){ ch = fgetc(f); while(ch != EOF && ch != ’\n’ && ch != ’:’ && ch != ’,’){ zapisznak(ch, &nekos); ch = fgetc(f); } label = zestringuj(&nekos); smazstr(&nekos);
102
24 Modul languages
Program kraluk
124: 125: upravstring(label); 126: if(label[0]){ 127: ppin = hash_find(WORD, label); 128: if(ppin) pop->slovo = ((struct slovo *)ppin->u.p)->ulozeno; 129: if(!pop->slovo) warning("nepochopeno slovo %s v outputu", label); 130: } 131: free(label); 132: if(ch == ’:’) zadvojteckou = 1; 133: } 134: 135: if(ch != ’,’) break; 136: 137: pop = (kq_output *)mymalloc(sizeof(kq_output)); 138: pop->orig = 0; 139: addPdoL(pop, &oplist); 140: ch = fgetc(f); 141: while(ch == ’ ’ || ch == ’\t’ || ch == ’\n’) ch = fgetc(f); 142: } 143: 144: zacatekr = prazdnyr = 1; 145: mezera = 0; 146: pocetenteru = 0; 147: } 148: else if(op){ 149: for(;pocetenteru; pocetenteru--) zapisznak(’\n’, &nekos); 150: if(mezera){ 151: zapisznak(’ ’, &nekos); 152: mezera = 0; 153: } 154: zapisznak(ch, &nekos); 155: prazdnyr = 0; 156: } 157: } 158: 159: fclose(f); 160: free(fullname); 161: }
Položka orig ve struktuře kq_word udává, jestli při uvolňování z paměti má být uvolněn i string. Je to tedy nastaveno na false, pokud byl labelík napsán za čárkou.
24 Modul languages V tento modul řeší přepínání jazyků. Při startu programu je načten soubor _languages.txt z adresáře s ostatními jazykovými soubory a v něm se program dozví o dostupných jazycích. Každý neprázdný řádek obsahuje nejprve zkratku jazyka, tedy to, čím začínájí soubory toho jazyka, pak následuje rovnítko a pak název jazyka. Takový soubor může vypadat například takto: cs = cestina cz = čeština en = english Tomu, co je před rovnítkem, jsou jen odebrány mezery z krajů, ale na to, co je za rovnítkem, je aplikována funkce upravstring. To proto, že název slouží jako slovo, které když se napíše, přepne se do příslušného jazyka. Pokud na řádku ovšem žádné rovnítko není, je do názvu dosazena zkratka jazyka. Tato zkratka však takto upravována není, takže pokud obsahuje něco neobvyklého, nemůže být jakožto slovo nalezena. Seznam jazyků jsou jen propojené datové typy kq_word, kde první jazyk je prvlang. Tato slova nejsou začleněna do seznamu začínajícího proměnnou prvulslovo a jejich typ je LANGWORD. Díky tomu nemůže být uložen ukazatel na takové slovo. Při načítání jsou tato slova řazena do fronty tak, že poslední prvek je aktulang. Později aktulang ukazuje na slovo aktuálního jazyku. kq_word *prvlang: 104–105, 108, 162, 187
kq_word *aktulang: 103–108, 161–162, 187
103
24 Modul languages
Program kraluk languages.c
17: kq_word *aktulang = NULL; 18: kq_word *prvlang = NULL;
Do položky nazev v kq_word je uložen název jazyka, jeho zkratka je uložena do položky informace jakožto pinpointer. Položka kontext je vždy nastavena na jedničku. languages.c 20: void nactijazyky () 21: { 22: char *fullname, *str; 23: FILE *f; 24: kq_string nekos; 25: char ch; 26: int i; 27: 28: fullname = joinstrings(DATADIR, LANGDIR, LANGFILE, NULL); 29: if((f = fopen (fullname, "r")) == NULL){ 30: warning("Nepovedlo se otevrit soubor %s", fullname); 31: free(fullname); 32: return; 33: } 34: 35: initstr(&nekos); 36: for(;;){ 37: ch = fgetc(f); 38: if(ch == EOF) break; 39: 40: while(ch == ’ ’ || ch == ’\t’) ch = fgetc(f); 41: while(ch != ’=’ && ch != ’\n’ && ch != EOF){ 42: zapisznak(ch, &nekos); 43: ch = fgetc(f); 44: } 45: str = zestringuj(&nekos); 46: for(i = nekos.delka-1; i >= 0 && (str[i] == ’ ’ || str[i] == ’\t’); i--); 47: str[i+1] = 0; 48: smazstr(&nekos); 49: if(!str[0] && ch != ’=’){ 50: free(str); 51: continue; 52: } 53: 54: if(aktulang){ 55: aktulang->next = (kq_word *)mymalloc(sizeof(kq_word)); 56: aktulang = aktulang->next; 57: } 58: else prvlang = aktulang = (kq_word *)mymalloc(sizeof(kq_word)); 59: 60: aktulang->informace = pinpointer(str); 61: aktulang->typ = LANGWORD; 62: aktulang->kontext = 1; 63: aktulang->next = NULL; 64: 65: if(ch == ’=’){ 66: ch = fgetc(f); 67: while(ch != ’\n’ && ch != EOF){ 68: zapisznak(ch, &nekos); 69: ch = fgetc(f); 70: } 71: aktulang->nazev = zestringuj(&nekos); 72: upravstring(aktulang->nazev); 73: if(!aktulang->nazev[0]){ 74: free(aktulang->nazev); 75: aktulang->nazev = NULL; 76: } 77: smazstr(&nekos); 78: } 79: else aktulang->nazev = str; 80: }
104
24 Modul languages
Program kraluk
81: fclose(f); 82: free(fullname); 83: }
Předtím než začne být načítán jazyk, přičlení tento modul svá data ke slovům a větám, čímž zařídí, že napsáním názvu jazyka je do tohoto jazyka přepnuto. To udělá funkcí jazslova. languages.c 85: static void jazslova () 86: { 87: kq_word *pom; 88: struct slovo *slovo; 89: struct veta *puvveta; 90: kq_pin p; 91: 92: p = pinint(1); 93: hash_add(WORDCAT, LANGCAT, &p); 94: 95: for(pom=prvlang; pom; pom = pom->next){ 96: if(pom->nazev){ 97: slovo = (struct slovo *)mymalloc(sizeof(struct slovo)); 98: slovo->pocet = 1; 99: slovo->makro = 0; 100: slovo->kateg = (int *)mymalloc(2*sizeof(int)); 101: slovo->kateg[0] = 1; 102: slovo->kateg[1] = 0; 103: slovo->u.vety = NULL; 104: slovo->ulozeno = pom; 105: 106: wordtohash(slovo, pom->nazev); 107: } 108: } 109: 110: puvveta = jenkat; 111: jenkat = (struct veta *)mymalloc(sizeof(struct veta)); 112: jenkat->funkce = prepnilang; 113: jenkat->pocetclenu = 1; 114: jenkat->pocetparam = 1; 115: jenkat->cleny = (struct vetnyclen *)mymalloc(sizeof(struct vetnyclen)); 116: jenkat->cleny->jekat = 1; 117: jenkat->cleny->u.kateg = (int *)mymalloc(sizeof(int)); 118: jenkat->cleny->u.kateg[0] = 1; 119: jenkat->cleny->u.kateg[1] = 0; 120: jenkat->cleny->mistoparam = 0; 121: jenkat->next = puvveta; 122: }
Při startu programu je spuštěna funkce startlang, která spustí jazslova a pak tedy načte příslušné soubory. languages.c 188: void startlang () 189: { 190: jazslova(); 191: if(aktulang){ 192: nactiinput(aktulang->informace.u.p); 193: nactioutput(aktulang->informace.u.p); 194: } 195: }
Pro změnu jazyka existuje funkce zmenlang. Té je předán kq_word toho jazyka, do kterého chci přepnout. Tato funkce nejprve vymaže původní jazyk a pak načte nový. Před tím musí ovšem opět aplikovat jazslova, protože odlišovat při rušení jazyka standardní slova od slov jazyka by bylo příliš komplikované.
void jazslova /*languages*/ (): 105–106
void startlang(): 105, 188
105
void zmenlang(): 106–108
24 Modul languages
Program kraluk languages.c
197: void zmenlang (kq_word *jazyk) 198: { 199: aktulang = jazyk; 200: zrusjazyk(); 201: jazslova(); 202: nactiinput(jazyk->informace.u.p); 203: nactioutput(jazyk->informace.u.p); 204: }
Rušení jazyka ovšem vůbec není žádná sranda. Je třeba projít hashovou tabulku a smazat z ní ty položky, které se týkají inputu nebo outputu. Kromě toho je třeba uvolnit z paměti další záležitosti, co se toho týkají. Základní funkce pro mazání jazyka je zrusjazyk. Tato funkce prochází hash a pak volá další specializované funkce. languages.c 161: static void zrusjazyk () 162: { 163: int i; 164: struct hash **pom, *pomo, *pomoc; 165: 166: // prochazim hashove pole: 167: for(i=0; inext){ 170: // prochazim a mazu hashove polozky, co maji byt smazany 171: for(pomo = *pom; pomo && (pomo->typ == WORD || pomo->typ == WORDPART || 172: pomo->typ == WORDCAT || pomo->typ == OUTPUT); 173: pomo = pomo->next){ 174: pomoc = pomo->next; 175: if(pomo->typ == OUTPUT) freeoutputs(pomo->informace.u.p); 176: if(pomo->typ == WORD) freeword(pomo->informace.u.p); 177: free(pomo->string); 178: free(pomo); 179: } 180: *pom = pomo; 181: if(!pomo) break; 182: } 183: 184: freesents(jenkat); 185: jenkat = NULL; 186: }
Seznam outputů z jednoho hashového políčka smaže funkce freeoutputs. String uvolní jen v případě, že položka orig je true. Pokud totiž existuje více outputů s jedním stringem, má orig nastavený na true právě jeden z nich (ten, co byl uveden v souboru jako první). languages.c 150: static void freeoutputs (kq_output *o) 151: { 152: kq_output *o2; 153: 154: for(; o; o=o2){ 155: o2 = o->next; 156: if(o->orig) free(o->str); 157: free(o); 158: } 159: }
Slovo z hashového políčka smaže funkce freeword. Jedno slovo však v hashi může být zaneseno vícekrát. Skutečné uvolňování z paměti tedy zahájím až když je tato funkce na daný pointer zavolána naposled. languages.c 139: static void freeword (struct slovo *w) 140: { 141: w->pocet--; 142: if(w->pocet) return; void zrusjazyk /*languages*/ (): 106 /*languages*/ (): 106
void freeoutputs /*languages*/ (): 106
106
void freeword
24 Modul languages 143: 144: 145: 146: 147: 148: }
Program kraluk
if(w->makro) smazlist(&w->u.nahradit); else freesents(w->u.vety); if(w->kateg) free(w->kateg); free(w);
Při mazání slova také uvolňuji seznam vět funkcí freesents. Také je třeba smazat věty ze seznamu jenkat. languages.c 124: static void freesents (struct veta *v) 125: { 126: int i; 127: struct veta *v2; 128: 129: for(; v; v = v2){ 130: for(i=0; i < v->pocetclenu; i++) 131: if(v->cleny[i].jekat && v->cleny[i].u.kateg) 132: free(v->cleny[i].u.kateg); 133: free(v->cleny); 134: v2=v->next; 135: free(v); 136: } 137: }
Tímto funkce pro mazání končí. Další funkce v tomto modulu je ta, která je zavolána při napsání slova jazyka, tedy funkce prepnilang. Tato funkce, kromě toho, že zavolá zmenlang, vypíše hlášku ohledně přepnutí jazyka. První část hlášky je vytáhnuta z outputu nového jazyka pod labelíkem _language start a druhá část hlášky je vytáhnuta z outputu starého jazyka pod labelíkem _return to language. Pokud je napsané slovo stejné jako zvolený jazyk, vypíše z outputu hlášku pod labelíkem same language. languages.c 206: void prepnilang (int pocet, kq_word **jazslovo) 207: { 208: char *jaznavrat, *jazprichod, *popstr; 209: 210: if(pocet != 1){ 211: warning("prepnilang: spatny pocet slov"); 212: return; 213: } 214: 215: if(jazslovo[0]->typ != LANGWORD){ 216: warning("prepnilang: jazslovo[0]->typ != LANGWORD"); 217: return; 218: } 219: 220: if(jazslovo[0] == aktulang){ 221: popup_info("_same language"); 222: return; 223: } 224: 225: jaznavrat = outputstring("_return to language", NULL); 226: if(jaznavrat) jaznavrat = dupstr(jaznavrat); 227: 228: zmenlang(jazslovo[0]); 229: 230: jazprichod = outputstring("_language start", NULL); 231: if(jazprichod){ 232: if(jaznavrat) popstr = joinstrings(jazprichod, "\n", jaznavrat, NULL); 233: else popstr = jazprichod; 234: popupstring(DEF_POP_SIRKA, DEF_POP_VYSKA, DEF_POP_X, DEF_POP_Y, popstr, 0); 235: if(popstr != jazprichod) free(popstr); 236: } 237: else popup_info("_language start"); 238: void freesents /*languages*/ (): 106–107
void prepnilang /*languages*/ (): 105, 107
107
25 Modul edit
Program kraluk
239: if(jaznavrat) free(jaznavrat); 240: }
Poslední funkce je ta, která zobrazí seznam jazyků, tedy ta, co je spuštěna klávesou F12, jmenuje se zobrazjazyky. Nejprve funkce připravi pole pro funkci popupselect a pak je přepnuto do toho jazyka, který si uživatel vybere. Nic se nestane, pokud je výběr ukončen klávesou Escape nebo když je vybrán stejný jazyk jako na začátku. Nadpis výběru si funkce vytáhne z outputu pod labelíkem _languages. languages.c 242: void zobrazjazyky () 243: { 244: char **jazlist; 245: kq_word *pom; 246: int i, aktu; 247: 248: i=1; 249: for(pom = prvlang; pom; pom = pom->next){ 250: if(!pom->nazev){ 251: warning("neznamy nazev jazyku \"%s\"", pom->informace.u.p); 252: return; 253: } 254: if(pom == aktulang) aktu = i-1; 255: i++; 256: } 257: 258: jazlist = (char **)mymalloc(i*sizeof(char *)); 259: 260: i=0; 261: for(pom = prvlang; pom; pom = pom->next){ 262: jazlist[i] = pom->nazev; 263: i++; 264: } 265: jazlist[i] = NULL; 266: 267: i = popupselect(DEF_POP_SIRKA, DEF_POP_VYSKA, DEF_POP_X, DEF_POP_Y, 268: outputstring("_languages", NULL), 269: jazlist, aktu, NULL); 270: free(jazlist); 271: 272: if(i >= 0 && i != aktu){ 273: for(pom = prvlang; i; i--) pom = pom->next; 274: zmenlang(pom); 275: } 276: }
25 Modul edit Tento modul řěší editaci textu ve spodním řádku. Xlib samotný totiž nic takového neumí. Napsaný string je uložen v proměnné editpole. Na ni ukazuje proměnná text_pole. Obvykle je tedy text_pole a editpole to samé. Začne se to lišit až v nestandardních případech, například při procházení historie. edit.c 23: static char editpole[STRINGSIZE]; 24: char *text_pole = editpole;
Neukládám však zde string standardním C-čkovým způsobem. Pole editpole není zakončeno nulou, ale místo toho je délka stringu uložená v proměnné delka. Dále je tu proměnná cursor, která určuje místo v textu, kam se píše. Pokud cursor == 0, je kursor nejvíce vlevo, a když cursor == delka, tak je nejvíc vpravo. edit.c 20: static int cursor = 0; 21: static int delka = 0;
void zobrazjazyky(): 20, 108, 217 char *editpole /*edit*/ : 108, 110, 112, 114–118 char *text_pole: 108–112, 114–118, 163–165 int delka /*edit*/ : 108–112, 114–118
108
25 Modul edit
Program kraluk
Funkce loadfont načte font ze stringu FONTNAME do font_info a nastaví související proměnné. Je nastavena výška okénka s textem (text_vyska), dále kursor_vyska, což udává výšku kursoru, která ovšem není stejná jako text_sirka, ale je užší o HOT (horní okraj textu ) a DOT (dolní okraj textu). Proměnná font_y udává vzdálenost od horního okraje textwin k účaří, tedy ypsilonová souřadnice, co se má použít při vykreslení textu. edit.c 29: void loadfont () 30: { 31: if ((font_info=XLoadQueryFont(display, FONTNAME)) == NULL) 32: error("cannot open %s font", FONTNAME); 33: 34: kursor_vyska = font_info->ascent+font_info->descent; 35: text_vyska = HOT+kursor_vyska+DOT; 36: font_y = HOT+font_info->ascent; 37: }
Text je pak zobrazen v okně textwin. K tomu mám ještě dvě proměnné. Proměnná gelka (grafická délka) určuje vzdálenost konce textu od začátku textového políčka a proměnná gursor (grafický cursor) určuje vzdálenost kursoru od začátku textového políčka. V případě, že je text prázdný, tedy delka = 0, tak proměnné gelka i gursor jsou nastaveny na LOT (levý okraj textu). Text vykreslí funkce redrawtext. Proměnná posunuti má zápornou hodnotu jen v případě, že je text zobrazen poprvé. V takovém případě je spočtena počáteční gelka a gursor. Funkce redrawtext je volána po rozsáhlé úpravě textu nebo při odkrytí okna. edit.c 45: void redrawtext () 46: { 47: if(posunuti < 0){ 48: posunuti = 0; 49: gursor = LOT; 50: gelka = LOT; 51: if(delka) gelka += XTextWidth(font_info, text_pole, delka); 52: if(cursor) gursor += XTextWidth(font_info, text_pole, cursor); 53: if(posuntext()) return; 54: } 55: 56: if(delka){ 57: XDrawString(display, textwin, text_gc, 58: LOT-posunuti, font_y, text_pole, delka); 59: 60: // Nakreslim okraje po stranach: 61: 62: if(posunuti) 63: XClearArea(display, textwin, 0, 0, 64: LOT, text_vyska, 0); 65: 66: if(gelka > text_sirka-POT) 67: XClearArea(display, textwin, text_sirka-POT, 0, 68: POT, text_vyska, 0); 69: } 70: 71: if(okrajtext) ukazkursor(); 72: }
Funkce cleartext text smaže, pouze však graficky. Tedy vyčistí textové políčko. edit.c 39: void cleartext () 40: { 41: XClearArea(display, textwin, 0, 0, 42: text_sirka, text_vyska, 0); 43: } void loadfont(): 39, 109 char *FONTNAME: 10, 109 XFontStruct *font_info: 40, 109–112, 116–117, 188 int kursor_vyska /*edit*/ : 109–110 int HOT: 10, 109–110 int DOT: 10, 109 int font_y /*edit*/ : 109–111 int gelka /*edit*/ : 109–113, 115–117 int gursor /*edit*/ : 109–113, 115–117 void redrawtext(): 25, 109, 113, 116–117, 120, 123, 165 void cleartext(): 109–110, 112–113, 116–117, 165
109
25 Modul edit
Program kraluk
Kursor je bílý obdélníček, jehož levý okraj je na pozici gursor a má šířku podle hodnoty KURSIR. Vykreslí ho funkce ukazkursor. edit.c 74: void ukazkursor () // vykresli kursor 75: { 76: XFillRectangle(display, textwin, text_gc, gursor, HOT, 77: KURSIR, kursor_vyska); 78: }
Funkce smazkursor kursor smaže. To je o něco složitější než jeho vykreslení, protože je třeba pak ještě znovu vykreslit písmenko, které bylo pod ním. Předpokládá se, že kursor je natolik úzký, že se pod něj vejde jen jedno písmenko. edit.c 80: void smazkursor () // smaze kursor 81: { 82: XClearArea(display, textwin, gursor, HOT, 83: KURSIR, kursor_vyska, 0); 84: 85: if(cursor < delka) // obnovim smazane pismeno 86: XDrawString(display, textwin, text_gc, gursor, font_y, 87: &(text_pole[cursor]), 1); 88: }
Základ editace textu je psaní písmen. Při stisku klávesy, která je znakem, je zavolána funkce pripisznak. Tato funkce dostane znak, který má připsat. Pokud je již pole plné, vrátí nulu. Jinak připíše znak do místa kursoru a pak bude návratová hodnota záporná v případě, že byl znak připsán na konec. Návratové hodnoty jsou využity při vybírání souborů. Tato funkce musí jak graficky, tak v poli posunout znaky za napsaným znakem. edit.c 258: char pripisznak (char ch) 259: { 260: int i, sirka; 261: 262: if(!okrajtext){ // Je-li aktivni okno, smazu a zaktivnim text. 263: okraj_to_text(); 264: cursor = delka = 0; 265: gursor = gelka = LOT; 266: cleartext(); 267: aktuhist = -1; 268: text_pole = editpole; 269: } 270: 271: if(delka == STRINGSIZE) return 0; // Doslo mi pole 272: 273: edithist(); // Prepnu se do editacniho radku. (pokud tam nejsem) 274: 275: for(i=delka-1; i >= cursor; i--) 276: text_pole[i+1] = text_pole[i]; // Posunu znaku za kursorem. (v poli) 277: text_pole[cursor] = ch; // Ulozim novy znak 278: 279: sirka = XTextWidth(font_info, &ch, 1); // Zjistim sirku pismena. 280: 281: // Posunu kursor, zvetsila se delka: 282: delka++; 283: cursor++; 284: gursor += sirka; 285: gelka += sirka; 286: 287: if(posuntext()){ // Pokud se mi text posune, mam grafiku vyresenou. 288: if(cursor == delka) return -1; 289: else return 1; 290: } 291: 292: XClearArea(display, textwin, gursor-sirka, 0, // Smazu kursor nebo text za kursorem. int KURSIR: 10, 110–111 void ukazkursor(): 109–113, 116, 164 117, 164 char pripisznak(): 25, 110, 120, 164
110
void smazkursor(): 110, 112–113,
25 Modul edit 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: }
Program kraluk
(gelka-gursor > KURSIR) ? (gelka-gursor):KURSIR, text_vyska, 0); // Vykreslim text, co jsem napsal a posunul: XDrawString(display, textwin, text_gc, gursor-sirka, font_y, &(text_pole[cursor-1]), delka-cursor+1); if(gelka > text_sirka-POT) // cerny okraj na prave strane textoveho okenka XClearArea(display, textwin, text_sirka-POT, 0, POT, text_vyska, 0); ukazkursor(); if(cursor == delka) return -1; else return 1;
Další editační funkce je delete, která jeden znak smaže. Tato funkce dostane parametr, který, když je true, tak bude smazán znak před kursorem, jinak bude smazán znak za kursorem. Pokud se smazání podaří, vrátí funkce jedničku, jinak vrátí nulu. edit.c 325: char delete (int backspace) 326: { 327: int i, puvgelka; 328: 329: if(backspace){ // Prevedu backspace na delete 330: if(!cursor) return 0; 331: cursor--; 332: gursor -= XTextWidth(font_info, &(text_pole[cursor]), 1); 333: } 334: 335: if(delka == cursor) return 0; // Jsem na konci radku. 336: 337: edithist(); // Prepnu se do editacniho radku. (pokud tam nejsem) 338: 339: puvgelka = gelka; 340: 341: delka--; // Zmensila se delka textu. 342: gelka -= XTextWidth(font_info, &(text_pole[cursor]), 1); 343: 344: for(i=cursor; i<delka+1; i++) // posunu zbyle znaky za kursorem. 345: text_pole[i] = text_pole[i+1]; 346: 347: if(posuntext()) // Pokud se mi text posune, mam grafiku vyresenou. 348: return 1; 349: 350: // Smazu text pred kursorem i s kursorem, co tam mohl zbyt z backspace. 351: XClearArea(display, textwin, gursor, 0, 352: puvgelka-gursor+KURSIR, text_vyska, 0); 353: 354: if(delka != cursor) 355: XDrawString(display, textwin, text_gc, gursor, // Vykreslim zbyle znaky za kursorem. 356: font_y, &(text_pole[cursor]), delka-cursor); 357: 358: ukazkursor(); 359: return 1; 360: }
Kursor samozřejmě mohu posunovat. Obecná funkce pro tento účel je posunkursor. Tato funkce má jeden parametr, který určuje, zda se má kursor posunout na konec, na začátek, doleva nebo doprava. edit.c 362: void posunkursor (int jak) 363: { 364: // jak: 0=left, 1=right, 2=home, 3=end 365: 366: if((!(jak%2) && !cursor) || ((jak%2) && cursor == delka)) return; 367: // Nemohu posunou kursor podle promenne jak. char delete(): 20–21, 111, 164
void posunkursor(): 21, 111, 115, 164
111
25 Modul edit 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: }
Program kraluk
smazkursor(); // Zmenim cursor a gursor: switch((jak)){ case 0: cursor--; gursor -= XTextWidth(font_info, &(text_pole[cursor]), 1); break; case 1: gursor += XTextWidth(font_info, &(text_pole[cursor]), 1); cursor++; break; case 2: cursor = 0; gursor = LOT-posunuti; break; case 3: gursor = gelka; cursor = delka; } if(!posuntext()) // Pripadne posunu text. ukazkursor();
Při zmáčknutí enteru se spustí text_enter, což text vynuluje a provede. edit.c 440: void text_enter () 441: { 442: char povedlo, bylot; 443: int i; 444: 445: for(i=0; i<delka && !isalpha(text_pole[i]); i++); 446: 447: if(i == delka){ // pokud v textu neni zadny znak, 448: zkoumejhist(2); // neminim se s nim obtezovat 449: return; 450: } 451: 452: ulozhist(); // Ulozim text do historie, 453: aktuhist = -1; 454: text_pole = editpole; 455: 456: // smazu ho: 457: 458: cleartext(); 459: posunuti = cursor = delka = 0; 460: gursor = gelka = LOT; 461: bylot = okrajtext; 462: okraj_to_win(); 463: 464: // a provedu 465: 466: povedlo = provedstr(history[poslhist]); 467: 468: if(bylot && !povedlo){ 469: okraj_to_text(); // V pripade neuspechu se vratim do editacniho radku 470: ukazkursor(); 471: } 472: 473: return; 474: }
void text_enter(): 20, 112
112
25 Modul edit
Program kraluk
Při zmáčknutí tabelátoru se spustí funkce prepniokraj. Ta dostane parametr o tom, zda se má okraj přepnout na text (true) nebo na okno (false). edit.c 313: void prepniokraj (int natext) 314: { 315: if(natext){ // Da okraj na textwin 316: ukazkursor(); 317: okraj_to_text(); 318: } 319: else{ // Da okraj na win 320: smazkursor(); 321: okraj_to_win(); 322: } 323: }
Připisováním písmen by se mohlo stát, že mi kursor uteče mimo obrazovku. To však není žádoucí. Proto je možné text posouvat. To, o kolik pixelů je text posunut směrem doleva, udává proměnná posunuti. edit.c 18: static int posunuti = -1;
I když je text posunutý, gursor i gelka se stále vztahuje k začátku okna a nikoliv k začátku textu. Při změně proměnné gursor, gelka či text_sirka je zavolána funkce posuntext. Pokud tato funkce usoudí, že je vhodné text posunout, vrátí true, změní proměnné posunuti, gelka a gursor a tuto změnu aplikuje i graficky. Tudíž po úspěšném posunutí textu není třeba již řešit grafické záležitosti. Funkce posuntext se snaží o splnění následujících podmínek, přičemž podmínky, co jsou napsány výše, mají vyšší prioritu: 1) Levý okraj textu bude LOT pixelů od okraje okénka nebo více vlevo. Tedy posunuti >= 0. 2) Pravý okraj textu bude POT pixelů od okraje okénka nebo více vpravo. Tedy gelka <= text_sirka-POT. 3) Kursor bude dostatečně daleko od okraje. Tedy gursor >= STRKAL && gursor <= text_sirka-STRKAP. 4) Text se posune co nejméně. Tedy ppos bude minimální. edit.c 104: char posuntext () 105: { 106: int ppos = 0; 107: 108: if(gursor < STRKAL) ppos = STRKAL-gursor; // pravidlo 3 109: else if(gursor > text_sirka-STRKAP) ppos = text_sirka-STRKAP-gursor; 110: 111: if(gelka+ppos < text_sirka-POT) ppos = text_sirka-POT-gelka; // pravidlo 2 112: 113: if(posunuti-ppos < 0) ppos = posunuti; // pravidlo 1 114: 115: if(!ppos) return 0; 116: 117: posunuti -= ppos; 118: gursor += ppos; 119: gelka += ppos; 120: cleartext(); 121: redrawtext(); 122: return 1; 123: }
void prepniokraj(): 20, 113 int posunuti /*edit*/ : 109, 112–113, 115–117 char posuntext(): 43, 109–113, 116–117 intLOT: 10, 109–110, 112, 116–117 int POT: 10, 109, 111, 113 int STRKAL: 10, 113 int STRKAP: 10, 113
113
25 Modul edit
25.1
Program kraluk
historie
Vždy, když je odenterován nějaký neprázdný text, je uložen do historie. Historie je zastoupena polem stringů history, které má délku MAXHISTORY. Stringy v tomto poli však jsou standardně C-čkovské, tedy zakončeny nulou. edit.c 142: static char *history[MAXHISTORY];
Nejprve je historie uložena do history[0], pak do history[1], pak do history[2], . . . Index pole, do kterého byla historie naposledy uložena, je uložený v proměnné poslhist. V případě, že jěště žádná historie uložena nebyla, poslhist = -1. Pokud už je zaplněna celá historie, tedy poslhist == MAXHISTORY-1, ukládám další historii opět do history[0], history[1], . . ., čímž přepisuji tu původní. Jakmile začnu takto přepisovat původní historii, nastavím cyklhist na true. Do té doby je cyklhist false. edit.c 131: 132: 133: 134:
Posledni radek, do ktereho se ukladala historie udava promenna poslhist. Pokud je historie prazdna, pak poslhist = -1. To, zda se uz historie zacala cyklit, cili pocet ulozenych radku dosahl maxima, je ulozeno v promenne cyklhist.
Při procházení historie používám proměnnou aktuhist. Pokud je tato proměnná nastavena na hodnotu −1, nejsem vůbec v historii a text_pole je nastaveno na editpole. Pokud aktuhist == -2, jsem v prázdném řádku. Tento prázdný řádek je to nejspodnější, co v historii je. Nad ním je editpole, nad ním history[poslhist] a dál už pokračuje obvyklá historie. V případě, že editpole je také prázdný, není možné se do historie −2 dostat. V případě, že poslhist = 3 a cyklhist = 0 historie tedy vypadá zhruba takto: history[0] history[1] history[2] history[3] editpole nic
aktuhist aktuhist aktuhist aktuhist aktuhist aktuhist
= 0 = 1 = 2 = 3 = -1 = -2
Funkce ulozhist uloží aktuální text do historie. Je v ní implementovaná ještě taková featura, že zkontroluje, zda je ukládaný text shodný s posledním uloženým a pokud ano, tak ho neukládá. Domnívám se, že text, který je v historii uložený dvakrát po sobě, tam akorát překáží. edit.c 170: void ulozhist () 171: { 172: int i; 173: 174: if(poslhist >= 0){ 175: for(i = 0; i<delka && history[poslhist][i] && 176: history[poslhist][i] == text_pole[i]; i++); 177: if(i == delka && !history[poslhist][i]) return; 178: // posledni historie je stejna, jakou bych mel ulozit 179: } 180: 181: // Posunu poslhist. 182: 183: poslhist++; 184: if(poslhist == MAXHISTORY){ 185: poslhist = 0; 186: cyklhist = 1; 187: } 188: 189: if(aktuhist == poslhist) return; /* Specialni pripad, kdy ukladam nejstarsi 190: historii a zaroven ji mazu */ 191: 192: if(cyklhist) free(history[poslhist]); // Uvolnim puvodni string. char **history /*edit*/ : 112, 114–116, 118 MAXHISTORY: 114–115, 118 int poslhist /*edit*/ : 112, 114–115, 118 char cyklhist /*edit*/ : 114–115, 118 int aktuhist: 110, 112, 114–118, 163, 165 void ulozhist(): 112, 114
114
25 Modul edit
Program kraluk
193: history[poslhist] = (char *)mymalloc((delka+1)*sizeof(char)); // Naalokuji novy string. 194: for(i=0; i<delka; i++) history[poslhist][i] = text_pole[i]; // Zkopiruji string. 195: history[poslhist][delka] = 0; // ZCeckuji ulozeny string. 196: }
Pro brouzdání historií se používá funkce zkoumejhist, která podobně jako funkce posunkursor má parametr jak. edit.c 394: void zkoumejhist (int jak) 395: { 396: // jak: 0=down, 1=up, 2=pgdown, 3=pgup 397: 398: if((!(jak%2) && (aktuhist == -2 || (aktuhist == -1 && !delka))) || 399: ((jak%2) && (aktuhist == (poslhist+1)%MAXHISTORY || 400: (aktuhist == 0 && !cyklhist) || 401: (poslhist == -1 && aktuhist == -1)))) return; 402: // Nemohu jit do historie podle promenne jak. 403: 404: if(aktuhist == -1) zalohujtext(&ocursor, &odelka, &ogursor, &ogelka, &oposunuti); 405: // Jsem-li na editacnim radku, ulozim si to. 406: 407: // Posunu aktuhist: 408: 409: switch(jak){ 410: case 0: 411: if(aktuhist == -1) aktuhist = -2; 412: else if(aktuhist == poslhist) aktuhist = -1; 413: else{ 414: aktuhist++; 415: if(aktuhist == MAXHISTORY) aktuhist = 0; 416: } 417: break; 418: case 1: 419: if(aktuhist == -1) aktuhist = poslhist; 420: else if(aktuhist == -2) aktuhist = -1; 421: else{ 422: aktuhist--; 423: if(aktuhist < 0) aktuhist += MAXHISTORY; 424: } 425: break; 426: case 2: 427: if(odelka) aktuhist = -2; 428: else aktuhist = -1; 429: break; 430: case 3: 431: if(poslhist == -1) aktuhist = -1; 432: else if(!cyklhist || poslhist == MAXHISTORY-1) aktuhist = 0; 433: else aktuhist = poslhist+1; 434: } 435: 436: dohistory(); // Aplikuji aktuhist. 437: if(!okrajtext) mengraf = 1; 438: }
V případě, že utíkám z editpole, uložím si proměnné cursor, delka, gursor, gelka a posunuti pomocí funkce zalohujtext do proměnných ocursor, odelka, ogursor, ogelka a oposunuti. edit.c 203: void zalohujtext (int *c, int *d, int *gc, int *gd, int *pos) 204: { 205: *c = cursor; 206: *d = delka; 207: *gc = gursor; 208: *gd = gelka;
void zkoumejhist(): 20–21, 112, 115, 117 void zalohujtext(): 115, 118, 163 int ocursor /*edit*/ : 115–116, 118 int odelka /*edit*/ : 115–116, 118 int ogursor /*edit*/ : 115–116, 118 int ogelka /*edit*/ : 115–116, 118 int oposunuti /*edit*/ : 115–116, 118
115
25 Modul edit
Program kraluk
209: *pos = posunuti; 210: }
Až se do editpole vrátím, zrestauruji výše zmíněné proměnné funkcí odzaltext. Tyto dvě funkce také umožňují ostatním modulům se do těchto statických proměnných dostat. edit.c 212: void odzaltext (int c, int d, int gc, int gd, int pos) 213: { 214: cursor = c; 215: delka = d; 216: gursor = gc; 217: gelka = gd; 218: posunuti = pos; 219: }
Funkce dohistory aplikuje aktuhist, tedy nastaví příslušné text_pole, delka, cursor, gelka, ... edit.c 226: void dohistory () 227: { 228: if(aktuhist == -2){ // Prazdny radek. 229: cleartext(); 230: gursor = gelka = LOT; 231: posunuti = cursor = delka = 0; 232: if(okrajtext) ukazkursor(); 233: } 234: else if(aktuhist == -1){ // Editacni radek, zrestauruji ulozene hodnoty. 235: cleartext(); 236: text_pole = editpole; 237: odzaltext(ocursor, odelka, ogursor, ogelka, oposunuti); 238: if(posunuti < 0 || !posuntext()) redrawtext(); 239: } 240: else{ // Skutecna historie 241: text_pole = history[aktuhist]; // Zmenim pointer text_pole. 242: posunuti = 0; 243: gelka = LOT; 244: delka = strlen(history[aktuhist]); // Spocitam delku 245: if(delka) gelka += XTextWidth(font_info, text_pole, delka); // Spocitam gelku 246: 247: // Kursor je na konci: 248: cursor = delka; 249: gursor = gelka; 250: 251: if(!posuntext()){ // Posunu text 252: cleartext(); // nebo ho jen prekreslim. 253: redrawtext(); 254: } 255: } 256: }
Otázka je, co se stane, když jsem v historii a začnu nějakým způsobem editovat. Některé programy fungují tak, že tím změním historii. Já však zastávám názor, že co se stalo se stalo a že historie je tu jen pro prohlížení. Tudíž když začnete historii editovat v tomto programu, přepnete se opět řádku editpole, kde proběhne úprava. Když se pak podíváte šipkou nahoru do historie, shledáte původní text nezměněn. Samožřejmě se tím však přepíše to, co bylo v proměnné editpole předtím. V editačních funkcích je tedy před provedením úpravy zavolána funkce edithist, která zaručí editaci editpole. edit.c 158: void edithist () 159: { 160: int i; 161: 162: if(aktuhist == -1) return; 163:
void odzaltext(): 116, 165
// Neni treba, pokud nejsem v historii.
void dohistory(): 115–116
116
void edithist(): 110–111, 116
25 Modul edit
Program kraluk
164: for(i=0; i<delka; i++) editpole[i] = text_pole[i]; // Zkopiruji string. 165: 166: aktuhist = -1; // Vratim aktuhist na editpole. 167: text_pole = editpole; // Vratim text_pole na editpole. 168: }
Dále stojí za povšimnutí, co vlastně udělá v textovém módu klávesa Escape. Ta totiž přepne okraj na win a zdánlivě vymaže text. Ve skutečnosti jen přepne historii na prázdný řádek. Stane se tedy to samé jako když zmáčknete PgDown a Tabelátor. edit.c 476: void text_escape () 477: { 478: int orihist; 479: 480: okraj_to_win(); 481: orihist = aktuhist; 482: zkoumejhist(2); 483: if(aktuhist == orihist) smazkursor(); 484: return; 485: }
25.2
Funkce pro ostatní
V tomto modulu jsou statické proměnné, které by rády měnily i jiné moduly. První dvě proměnné jsou určené pro modul gsl. Funkce zmentext dostane céčkovský string a ten zkopíruje do text_pole, přičemž nastaví i proměnné cursor, delka, gelka a gursor. edit.c 491: void zmentext (char *str) 492: { 493: for(delka=0; str[delka] && delka < STRINGSIZE; delka++) text_pole[delka] = str[delka]; 494: if(delka == STRINGSIZE && str[STRINGSIZE]) 495: warning("zmentext: prilis dlouhy text:\n %s\n", str); 496: posunuti = 0; 497: gelka = LOT; 498: if(delka) gelka += XTextWidth(font_info, text_pole, delka); // Spocitam gelku 499: 500: // Kursor je na konci: 501: cursor = delka; 502: gursor = gelka; 503: 504: if(!posuntext()){ // Posunu text 505: cleartext(); // nebo ho jen prekreslim. 506: redrawtext(); 507: } 508: }
Funkce textcstr funguje obráceně než zmentext. Tato funkce vrátí C-čkový string, který je zkonvertovaný z text_pole, který je nejčastěji stejný pointer jako text_pole. V opačném případě to je namallokovaný string. edit.c 510: char *textcstr () 511: { 512: if(delka == STRINGSIZE) return dupnstr(text_pole, delka); 513: text_pole[delka] = 0; 514: return text_pole; 515: }
Další dvě funkce jsou určeny pro moduly save a load. Funkce save_hist uloží historii pomocí ukládacích funkcí. Nejprve uloží počet uložených historií, pak aktuální historii, potom délky uložených historií, přičemž na začátku a nakonec uloží znaky. Přitom ukládá editpole stejně jako jednu z historií. edit.c 522: void save_hist () 523: { 524: int i, j, d;
void zmentext(): 117, 163–164
char *textcstr(): 117, 164
117
void save_hist(): 117, 161
25 Modul edit 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535: 536: 537: 538: 539: 540: 541: 542: 543: 544: 545: 546: 547: 548: 549: 550: 551: 552: 553: 554: }
Program kraluk
if(cyklhist) save_unsint(MAXHISTORY); else save_unsint(poslhist+1); if(aktuhist < 0) i = aktuhist; else{ i = poslhist - aktuhist; if(i < 0) i += MAXHISTORY; } save_unsint(i+2); d = delka; if(aktuhist != -1) d = odelka; save_unsint(d); for(i = poslhist; i >= 0;){ save_unsint(strlen(history[i])); i--; if(i < 0 && cyklhist) i += MAXHISTORY; if(i == poslhist) break; } save_cs(); for(j=0; j= 0;){ for(j=0; history[i][j]; j++) save_char(history[i][j]); i--; if(i < 0 && cyklhist) i += MAXHISTORY; if(i == poslhist) break; }
Funkce apply_loaded_hist dostane pole, délku historie a aktuální historii. Poslední prvek pole je uložen do editpole a ostatní do historie. edit.c 556: void apply_loaded_hist (char **hist, int poceth, int aktuh) 557: { 558: int i; 559: 560: poslhist = poceth-1; 561: cursor = delka = strlen(hist[poceth]); 562: for(i = 0; hist[poceth][i]; i++) editpole[i] = hist[poceth][i]; 563: free(hist[poceth]); 564: for(i = 0; i < poceth; i++) history[i] = hist[i]; 565: 566: if(aktuh != 1){ 567: zalohujtext(&ocursor, &odelka, &ogursor, &ogelka, &oposunuti); 568: if(aktuh > 1){ 569: aktuhist = poslhist-aktuh+2; 570: if(aktuhist < 0){ 571: warning("zaporne aktuhist"); 572: aktuhist = 0; 573: } 574: text_pole = history[aktuhist]; 575: delka = cursor = strlen(text_pole); 576: } 577: else{ 578: delka = cursor = 0; 579: aktuhist = -2; 580: } 581: } 582: }
void apply_loaded_hist(): 118, 161–162
118
26 Modul popup
Program kraluk
26 Modul popup Tento modul zobrazuje vyskakovací okna. Font, který se ve vyskakovacích oknech objevuje, nemusí být stejný jako font ve spodním editačním řádku. Tento modul tedy má vlastní funkci na načtení fontů, loadpopupfont. popup.c 27: void loadpopupfont () 28: { 29: popup_small_font = XLoadQueryFont(display, POPUPSMALLFONT); 30: popup_big_font = XLoadQueryFont(display, POPUPBIGFONT); 31: if(popup_small_font == NULL && popup_big_font == NULL) 32: error("cannot open %s font neither %s font", POPUPSMALLFONT, POPUPBIGFONT); 33: 34: if(popup_small_font == NULL){ 35: popup_small_font=popup_big_font; 36: warning("cannot open %s font", POPUPSMALLFONT); 37: } 38: if(popup_big_font == NULL){ 39: popup_big_font=popup_small_font; 40: warning("cannot open %s font", POPUPBIGFONT); 41: } 42: }
Tato funkce načte dva fonty. Do popup_small_font je načten font ze stringu POPUPSMALLFONT a do popup_big_font je načten font ze stringu POPUPBIGFONT. Při vyskočení okna je vybrán jeden z těchto fontů do proměnné pfont podle šířky win. To provede funkce vyberpfont. Font pfont je pak jediný font, co se používá. popup.c 44: static void vyberpfont () 45: { 46: if(win_sirka < POPUPBIGWIDTH) pfont = popup_small_font; 47: else pfont = popup_big_font; 48: }
Ve vyskakovacím okně může být buď text nebo výběr. Nejdřívě ukážu funkci popupstring, která zobrazí text. Tato funkce dostane rozměry a umístění okna a string, který má zobrazit. První čtyři parametry, rozměry a umístění, jsou reálnými čísly mezi nulou a jedničkou. Poslední parametr udává, zda se má při stisku libovolné klávesy okno zrušit. Nakonec vrátí funkce popupstring nulu v případě, že byla tato funkce ukončena klávesou Escape. Pokud se celý string nevejde do jednoho okna, funkce se zarekurzí a vytvoří tak další okno. Právě v případě klávesy Escape v rekurzi nepokračuje. popup.c 246: char popupstring (float fsirka, float fvyska, float fx, float fy, char *str, char vypnout) 247: { 248: int stringend; 249: KeySym ks; 250: char *ksname, ch; 251: XEvent report; 252: 253: pstr = dupstr(str); 254: vyberpfont(); 255: stringend = zalomstring(fsirka, fvyska, str); 256: createpwin(fx, fy); 257: 258: for(;;){ 259: XNextEvent(display, &report); 260: cekalose = 1; 261: if(report.type == KeyPress){ 262: if(vypnout || report.xkey.keycode == KEY_ESC || 263: report.xkey.keycode == KEY_ENTER || 264: report.xkey.keycode == KEY_SPACE) break; void loadpopupfont(): 39, 119 XFontStruct *popup_small_font: 119, 188 char *POPUPSMALLFONT: 10, 119 XFontStruct *popup_big_font: 119, 188 char * POPUPBIGFONT: 10, 119 XFontStruct *pfont /*popup*/ : 119–122, 124–126 void vyberpfont /*popup*/ (): 119, 123 int POPUPBIGWIDTH: 10 char popupstring(): 21, 99–100, 107, 119–120
119
26 Modul popup 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: }
Program kraluk
} if(report.type == ButtonPress) break; if(report.type == Expose){ if(report.xexpose.window == textwin) redrawtext(); else if(report.xexpose.window == pwin) drawpopup(0); else warning("divne expose"); } } XDestroyWindow(display, pwin); XFreeGC(display, pgc); free(pstr); mengraf = 1; if(report.type == KeyPress && report.xkey.keycode == KEY_ESC) return 0; if(vypnout && report.type == KeyPress && report.xkey.keycode != KEY_ENTER && report.xkey.keycode != KEY_SPACE){ XLookupString (&report.xkey, NULL, 0, &ks, NULL); if (ks != NoSymbol && (ksname = XKeysymToString (ks)) && dobind(ksname)) return 1; // zkusim spustit klavesovou zkratku ch = xkeyznak(&report); if(ch) pripisznak(ch); // nebo alespon pripsat zmacknuty znak do spodniho radku return 1; } if(str[stringend]) return popupstring(fsirka, fvyska, fx, fy, &str[stringend], vypnout); return 1;
Na začátku je string zduplikován do proměnné pstr a zalámán funkcí zalomstring. Tato funkce vrátí index znaku na kterém skončila, tedy pokud skončila tam, kde je v původním stringu nulový znak, vyčerpala celý string. Při lámání nahradí některé mezery enterem a vlnky nahradí mezerou, tedy vlnka je nezalomitelná mezera. Na konec tato funkce dá nulový znak. Funkce zalomstring se snaží vejít do okna o velikosti win_sirka*fsirka×win_sirka*fvyska. V případě, že funkce narazí na slovo širší než požadovaná šířka, tak šířku rozšíří a láme od začátku. Nakonec okno automaticky ořízne okolo textu a nastaví proměnné sirka a vyska. popup.c 50: static int zalomstring (float fsirka, float fvyska, char *str) 51: { 52: int i, j, k, x, y; 53: int maxx; 54: 55: sirka = win_sirka*fsirka - (2*(POPRAMOKR+POPRAMSIR) + POPLOT + POPPOT); 56: vyska = win_vyska*fvyska - (2*(POPRAMOKR+POPRAMSIR) + POPHOT + POPDOT); 57: 58: maxx = 0; 59: 60: y = 0; 61: 62: for(i=0; pstr[i];){ 63: x = 0; 64: y += pfont->ascent + pfont->descent; 65: if(y > vyska && i){ 66: y -= pfont->ascent+pfont->descent; 67: break; 68: } 69: y += INTERLINESKIP; 70: 71: for(k=j=i;;x += XTextWidth(pfont, " ", 1)){ 72: while(pstr[i] && pstr[i] != ’ ’ && pstr[i] != ’\n’) i++; 73: 74: x += XTextWidth(pfont, &pstr[k], i-k); 75: if(x > sirka){ 76: if(k == j){ 77: sirka = x; int zalomstring /*popup*/ (): 119–120, 124
120
26 Modul popup 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: }
Program kraluk
strncpy(pstr, str, i); i=0; maxx = 0; y = 0; break; } pstr[k-1] = ’\n’; i = k; break; } if(x > maxx){ maxx = x; } if(pstr[i] == 0) break; if(pstr[i] == ’\n’){ i++; break; } i++; k=i; } } pstr[i] = 0; for(i=0; pstr[i]; i++) if(pstr[i] == ’~’) pstr[i] = ’ ’; sirka = maxx; vyska = y-INTERLINESKIP; return i;
Poté, co je připravena velikost vyskakovacího okna v pixelech v proměnných sirka a vyska je zavolána funkce createpwin. Tato funkce rozměry okna ještě rozšíří o okraj skládající se z proměnných: POPRAMOKR (bílý okraj okolo černého rámečku), POPRAMSIR šířka čáry černého rámečku a POPLOT, POPPOT, POPHOT, POPDOT (pravý, levý, horní, dolní okraj textu). Pak spočítá X-ovou a Y-ovou souřadnici okna, vytvoří to okno a uloží ho do pwin. Kromě toho pro toto okno založí grafický kontext pgc, aby po něm mohlo být psáno. popup.c 111: static void createpwin (float fx, float fy) 112: { 113: int x, y; 114: 115: updateposts(); 116: 117: sirka += 2*(POPRAMOKR+POPRAMSIR) + POPLOT + POPPOT; 118: vyska += 2*(POPRAMOKR+POPRAMSIR) + POPHOT + POPDOT; 119: 120: x = (win_sirka-sirka)*fx; 121: y = (win_vyska-vyska)*fy; 122: 123: pwin = XCreateSimpleWindow(display, win, x, y, sirka, vyska, 0, 124: BlackPixel(display,screen), WhitePixel(display,screen)); 125: 126: pgc = XCreateGC(display, pwin, 0, NULL); 127: 128: XSetFont(display, pgc, pfont->fid); 129: XSetForeground(display, pgc, BlackPixel(display,screen)); 130: XSetLineAttributes(display, pgc, POPRAMSIR, LineSolid, CapButt, JoinMiter);
int sirka /*popup*/ : 119–124 int vyska /*popup*/ : 119–124 void createpwin(): 119, 121, 123 int POPRAMOKR: 10, 120–122, 124–126 int POPRAMSIR: 10, 120–122, 124–126 int POPLOT: 11, 120–122, 124–126 int POPPOT: 11, 120–121, 124 int POPHOT: 10–11, 120–122, 124–126 int POPDOT: 10, 120–122, 124–126 Window pwin /*popup*/ : 120–123, 125–126 GC pgc /*popup*/ : 120–123, 125
121
26 Modul popup
Program kraluk
131: 132: XSelectInput(display, pwin, ExposureMask); 133: 134: XMapWindow(display, pwin); 135: }
Jakmile je okno odkryto, je zavolána funkce drawpopup, která toto okno vykreslí/překreslí. To, zda se jedná o výběr, pozná podle parametru seznam, který je true v případě, že má být vykreslen výběr. V případě vykreslení seznamu tato funkce jen vykreslí okraj a nadpis. O vykreslení vnitřku se postará funkce drawselect. V případě vykreslování textu vykreslí rámeček a pak postupně vykresluje řádky. popup.c 213: void drawpopup (char seznam) 214: { 215: int x, y, i, j; 216: 217: x = y = POPRAMOKR + POPRAMSIR/2; 218: 219: XDrawRectangle(display, pwin, pgc, x, y, 220: sirka - 2*POPRAMOKR - POPRAMSIR, vyska - 2*POPRAMOKR - POPRAMSIR); 221: 222: x = POPRAMOKR+POPRAMSIR+POPLOT; 223: y = POPRAMOKR+POPRAMSIR+POPHOT+pfont->ascent; 224: if(seznam){ 225: if(pstr){ 226: XDrawString(display, pwin, pgc, x, y, pstr, strlen(pstr)); 227: y += pfont->descent+POPDOT; 228: if(selvyska) XFillRectangle(display, pwin, pgc, POPRAMOKR+POPRAMSIR, y, 229: sirka-2*POPRAMOKR-2*POPRAMSIR, POPRAMSIR); 230: y += POPRAMSIR+POPHOT+pfont->ascent; 231: } 232: drawselect(); 233: } 234: else{ 235: for(i=j=0; pstr[i]; i++){ 236: if(pstr[i] == ’\n’){ 237: if(j != i) XDrawString(display, pwin, pgc, x, y, &pstr[j], i-j); 238: j=i+1; 239: y += pfont->descent + INTERLINESKIP + pfont->ascent; 240: } 241: } 242: if(j != i) XDrawString(display, pwin, pgc, x, y, &pstr[j], i-j); 243: } 244: }
Druhou základní funkcí, která vytvoří vyskakovací okno je popup_select. Tato funkce kromě rozměrů dostane nadpis, který může být NULL, dále pole stringů, které je zakončené hodnotou NULL, potom index do pole, který bude jako první označen. Poslední parametr je ukazatel, který, pokud není NULL, bude propojen s proměnnou posunuti. Funkce popup_select nakonec vrátí index vybraného prvku. popup.c 403: int popupselect (float fsirka, float fvyska, float fx, float fy, 404: char *nadpis, char **pole, int aktu, int *posun) 405: { 406: if(!pole || !pole[0]){ 407: warning("empty popup select"); 408: return -1; 409: } 410: if(posun) posunuti = *posun; 411: else posunuti = 0; 412: 413: vytvorpsel(fsirka, fvyska, fx, fy, nadpis, pole, aktu, posunuti); 414: 415: XEvent report; void drawpopup(): 120, 122–123, 165
int popup_select(): 122
122
26 Modul popup 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: }
Program kraluk
for(;;){ XNextEvent(display, &report); cekalose = 1; if(report.type == KeyPress){ if(report.xkey.keycode == KEY_ESC){ aktuselect = -1; break; } else if(report.xkey.keycode == KEY_ENTER) break; else if(report.xkey.keycode == KEY_UP) posunselect(-1); else if(report.xkey.keycode == KEY_DOWN) posunselect(1); else if(report.xkey.keycode == KEY_LEFT) posunselect(-2); else if(report.xkey.keycode == KEY_RIGHT) posunselect(2); //printf("%d\n", report.xkey.keycode); } if(report.type == ButtonPress){ aktuselect = -1; break; } if(report.type == Expose){ if(report.xexpose.window == textwin) redrawtext(); else if(report.xexpose.window == pwin) drawpopup(1); else warning("divne expose"); } } zruspsel(); if(posun) *posun = posunuti; return aktuselect;
V modulu gsl zpracovávám události při otevřeném výběru jinak než ve funkci popupselect, takže pro vytvoření a zrušení vyskakovacího okna s výběrem tu jsou samostatné funkce. Funkce, která vytvoří okno s výběrem je vytvorpsel. Dostane skoro stejné parametry jako popupselect, ale posunuti nedostane jako ukazatel, ale rovnou jako číslo. popup.c 377: void vytvorpsel (float fsirka, float fvyska, float fx, float fy, 378: char *nadpis, char **pole, int aktu, int posun) 379: { 380: popvyber = pole; 381: aktuselect = aktu; 382: pstr = nadpis; 383: posunuti = posun; 384: 385: vyberpfont(); 386: spoctivyber(fsirka, fvyska); 387: createpwin(fx, fy); 388: }
Funkce zruspsel jednoduše smaže okno s výběrem. popup.c 390: void zruspsel () 391: { 392: XDestroyWindow(display, pwin); 393: XFreeGC(display, pgc); 394: mengraf = 1; 395: }
Proměnná pstr může být buď zobrazený string nebo nadpis výběru. Proměnná popvyber je pole stringů, které bylo zadáno funkci popupselect. Proměnná aktuselect je index do pole popvyber na
void vytvorpsel(): 122–123, 163, 165–166 void zruspsel(): 123, 165 char *pstr /*popup*/ : 119–126 char **popvyber /*popup*/ : 123–125 int aktuselect: 123–126, 163–164
123
26 Modul popup
Program kraluk
právě označený prvek a proměnná posunuti je index do pole popvyber na prvek, který je zobrazen vlevo nahoře. Při vytvoření okna s výběrem je potřeba spočítat rozměry okna podobně jako to dělá funkce zalomstring. Kromě toho, že funkce spoctivyber spočítá vhodné sirka a vyska, také uloží délku pole do parametru selpocet. Dále do proměné sloupec uloží délku jednoho sloupečku, do proměnné selsirka počet sloupečků, do proměnné selvyska počet řádků. Mezi řádky je stejně jako v případě standardního textu mezera INTERLINESKIP a mezi sloupci je mezera INTERCOLUMNSKIP. popup.c 294: static void spoctivyber (float fsirka, float fvyska) 295: { 296: int x, nadpissirka; 297: 298: if(!popvyber[0]){ 299: selsirka = selvyska = 0; 300: if(pstr){ 301: sirka = XTextWidth(pfont, pstr, strlen(pstr)); 302: vyska = pfont->ascent+pfont->descent; 303: } 304: else sirka = vyska = 0; 305: 306: return; 307: } 308: sirka = win_sirka*fsirka - (2*(POPRAMOKR+POPRAMSIR) + POPLOT + POPPOT); 309: vyska = win_vyska*fvyska - (2*(POPRAMOKR+POPRAMSIR) + POPHOT + POPDOT); 310: if(pstr){ 311: nadpissirka = XTextWidth(pfont, pstr, strlen(pstr)); 312: vyska -= POPHOT+pfont->ascent+pfont->descent+POPDOT+POPRAMSIR; 313: if(nadpissirka > sirka) sirka = nadpissirka; 314: } 315: else nadpissirka = 0; 316: 317: sloupec = 0; 318: for(selpocet = 0; popvyber[selpocet]; selpocet++){ 319: x = XTextWidth(pfont, popvyber[selpocet], strlen(popvyber[selpocet])); 320: if(x > sloupec) sloupec = x; 321: } 322: 323: selvyska = (vyska + INTERLINESKIP) / (pfont->ascent + pfont-> descent + INTERLINESKIP); 324: if(selvyska > selpocet) selvyska = selpocet; 325: if(selvyska < 1) selvyska = 1; 326: vyska = selvyska * (pfont->ascent + pfont-> descent + INTERLINESKIP) - INTERLINESKIP; 327: 328: selsirka = (sirka + INTERCOLUMNSKIP) / (sloupec + INTERCOLUMNSKIP); 329: if(selsirka > (selpocet-1)/selvyska) selsirka = (selpocet-1)/selvyska+1; 330: if(selsirka < 1) selsirka = 1; 331: sirka = selsirka * (sloupec + INTERCOLUMNSKIP) - INTERCOLUMNSKIP; 332: if(sirka < nadpissirka){ 333: sloupec = (nadpissirka+INTERCOLUMNSKIP)/selsirka - INTERCOLUMNSKIP; 334: sirka = nadpissirka; 335: } 336: 337: if(aktuselect < 0) aktuselect = 0; 338: if(aktuselect >= selpocet) aktuselect = selpocet-1; 339: 340: if(aktuselect < posunuti) posunuti = aktuselect; 341: else if(aktuselect >= posunuti + selvyska*selsirka) posunuti = aktuselect-selvyska*selsirka+1; 342: if(posunuti+selvyska*selsirka > selpocet) posunuti = selpocet-selvyska*selsirka; 343: if(posunuti < 0) posunuti = 0; 344: 345: if(pstr) vyska += POPHOT+pfont->ascent+pfont->descent+POPDOT+POPRAMSIR; int posunuti /*popup*/ : 122–126 void spoctivyber /*popup*/ : 123–124 int selpocet /*popup*/ : 124, 126 int sloupec /*popup*/ : 124–126 int selsirka /*popup*/ : 124, 126 int selvyska /*popup*/ : 122, 124–126 int INTERLINESKIP: 11, 120–122, 124–126 void INTERCOLUMNSKIP: 11, 124–126
124
26 Modul popup
Program kraluk
346: }
Jedna položka seznamu je označená tak, že je napsána bíle v černém obdélníčku. Tento obdélníček je na všechny směry o SELECTOKR větší. Předpokládá se však, že tento obdélníček nepřesahuje do ničeho jiného. Označenou položku vykreslím funkcí oznacsel. popup.c 137: void oznacsel () 138: { 139: int x, y; 140: 141: x = ((aktuselect-posunuti) / selvyska) * (sloupec+INTERCOLUMNSKIP) + 142: POPRAMOKR+POPRAMSIR+POPLOT; 143: y = ((aktuselect-posunuti) % selvyska) * (pfont->ascent+pfont->descent+INTERLINESKIP) + 144: POPRAMOKR+POPRAMSIR+POPHOT; 145: 146: if(pstr) y += pfont->descent+POPDOT+POPRAMSIR+POPHOT+pfont->ascent; 147: 148: XFillRectangle(display, pwin, pgc, x-SELECTOKR, y-SELECTOKR, 149: sloupec + 2*SELECTOKR, 150: pfont->ascent+pfont->descent+2*SELECTOKR); 151: XSetForeground(display, pgc, WhitePixel(display,screen)); 152: y += pfont->ascent; 153: XDrawString(display, pwin, pgc, x, y, popvyber[aktuselect], strlen(popvyber[aktuselect])); 154: XSetForeground(display, pgc, BlackPixel(display,screen)); 155: }
Označenou položku pak mohu opět odznačit funkcí odoznacsel. popup.c 157: void odoznacsel () 158: { 159: int x, y; 160: 161: x = ((aktuselect-posunuti) / selvyska) * (sloupec+INTERCOLUMNSKIP) + 162: POPRAMOKR+POPRAMSIR+POPLOT; 163: y = ((aktuselect-posunuti) % selvyska) * (pfont->ascent+pfont->descent+INTERLINESKIP) + 164: POPRAMOKR+POPRAMSIR+POPHOT; 165: 166: if(pstr) y += pfont->descent+POPDOT+POPRAMSIR+POPHOT+pfont->ascent; 167: 168: XClearArea(display, pwin, x-SELECTOKR, y-SELECTOKR, 169: sloupec + 2*SELECTOKR, 170: pfont->ascent+pfont->descent + 2*SELECTOKR, 0); 171: y += pfont->ascent; 172: XDrawString(display, pwin, pgc, x, y, popvyber[aktuselect], strlen(popvyber[aktuselect])); 173: }
Funkce drawselect vykreslí výběr. Pro vykreslení vybrané položky použije funkci oznacsel. popup.c 189: void drawselect () 190: { 191: int i, x, y, starty; 192: 193: if(pstr) starty = 2*POPRAMSIR+2*POPHOT+POPLOT+POPRAMOKR 194: +2*pfont->ascent+pfont->descent; 195: else starty = POPRAMSIR+POPHOT+POPRAMOKR+pfont->ascent; 196: x = POPRAMOKR+POPRAMSIR+POPLOT; 197: 198: y = starty; 199: 200: for(i=posunuti; popvyber[i];){ 201: if(i == aktuselect) oznacsel(); 202: else XDrawString(display, pwin, pgc, x, y, popvyber[i], strlen(popvyber[i])); 203: 204: if((++i-posunuti) % selvyska) y += pfont->descent + INTERLINESKIP + pfont->ascent; 205: else{ int SELECTOKR: 11, 125–126 void oznacsel(): 125–126, 164 void drawselect(): 122, 125–126, 163–164
125
void odoznacsel(): 125–126, 164
26 Modul popup
Program kraluk
206: if((i-posunuti) / selvyska >= selsirka) break; 207: y = starty; 208: x += sloupec + INTERCOLUMNSKIP; 209: } 210: } 211: }
Funkce clearselect smaže výběr, ale nechá nadpis a rámeček okolo. popup.c 175: void clearselect () 176: { 177: int x, y, s, v; 178: 179: x = POPRAMOKR + POPRAMSIR + POPLOT; 180: y = POPRAMOKR + POPRAMSIR + POPHOT; 181: if(pstr) y += pfont->ascent + pfont->descent + POPDOT + POPRAMSIR + POPHOT; 182: 183: s = (sloupec+INTERCOLUMNSKIP)*selsirka-INTERCOLUMNSKIP; 184: v = (pfont->ascent+pfont->descent+INTERLINESKIP)*selvyska-INTERLINESKIP; 185: 186: XClearArea(display, pwin, x-SELECTOKR, y-SELECTOKR, s+2*SELECTOKR, v+2*SELECTOKR, 0); 187: }
Při zmáčknutí šipky při otevřeném okně s výběrem, je zavolána funkce posunselect. Tato funkce dostane parametr, který může nabývat hodnot 1, 2, −1, −2. Dvojka znamená, že je posunuto o celou výšku, tedy doprava nebo doleva. V případě, že by aktuselect utekl mimo okno, je příslušně upraveno posunuti. popup.c 348: void posunselect (int okolik) 349: { 350: int naktu; 351: 352: if(okolik == 2) okolik = selvyska; 353: else if(okolik == -2) okolik = -selvyska; 354: 355: naktu = aktuselect + okolik; 356: if(naktu < 0) naktu = 0; 357: else if(naktu >= selpocet) naktu = selpocet-1; 358: 359: if(naktu == aktuselect) return; 360: 361: if(naktu < posunuti || naktu >= posunuti+selvyska*selsirka){ 362: posunuti += okolik; 363: if(posunuti < 0) posunuti = 0; 364: if(posunuti+selvyska*selsirka > selpocet) posunuti = selpocet-selvyska*selsirka; 365: 366: clearselect(); 367: aktuselect = naktu; 368: drawselect(); 369: } 370: else{ 371: odoznacsel(); 372: aktuselect = naktu; 373: oznacsel(); 374: } 375: }
Proměnná selpocet je statická, ale v modulu gsl ji někdy potřebuji změnit a navíc vynulovat posunuti. Od toho tu mám funkci popup_selpocet. popup.c 397: void popup_selpocet (int nsp) 398: { 399: selpocet = nsp; 400: posunuti = 0; 401: } void clearselect(): 126, 163–164 popup_selpocet(): 126, 163–164
void posunselect(): 123, 126, 164
126
void
27 Modul home
Program kraluk
27 Modul home Tento modul řeší manipulaci s domovským adresářem. Při startu je spuštěna funkce inithome, která zjistí domovský adresář, připojí k němu INHOMEDIR a uloží to do stringu homedir. V proměnné homedir tak je například: "/home/user/.kraluk". home.h 1: char *homedir; home.c 11: void inithome () 12: { 13: char *homename; 14: 15: homename = getenv("HOME"); 16: if(homename == NULL){ 17: warning("neznam domovsky adresar"); 18: homedir = NULL; 19: } 20: else homedir = joinstrings(homename, "/", INHOMEDIR, NULL); 21: }
Funkce homefopen otevře soubor v domovském adresáři a vrací stejný výsledek jako funkce fopen. Kromě zavolání funkce fopen však tato funkce ještě pro jistotu vytvoří domovský adresář funkcí mkdir. home.c 23: FILE *homefopen (const char *filename, const char *mode) 24: { 25: FILE *vysledek; 26: char *fullname; 27: 28: if(!homedir){ 29: warning("nebyl zjisten domovsky adresar"); 30: return NULL; 31: } 32: mkdir(homedir, 0777); 33: 34: fullname = joinstrings(homedir, "/", filename, NULL); 35: vysledek = fopen(fullname, mode); 36: free(fullname); 37: return vysledek; 38: }
28 Moduly save a load Modul save řeší ukládání aktuální pozice do souboru. Z tohoto souboru může být tato pozice načtena pomocí modulu load. 28.1
Základní načítací a ukládací funkce
Při ukládání je třeba nejprve otevřít soubor do proměnné soubor. To dělá funkce save_start. Kromě toho připraví další proměnné související s ukládáním. Jedna z nich je proměnná chyba, která, pokud je nastavena na true, značí, že něco není v pořádku a je tedy nejlepší ukládání ukončit. save.c 30: static char chyba; 31: static FILE *soubor; save.c 70: void save_start (char *filename) 71: { 72: int i; 73: 74: chyba = 0; 75: soubor = homefopen(filename, "w"); 76: void inithome(): 127, 187 char *homedir: 127, 130, 160–161, 165–166, 188 FILE *homefopen(): 127, 129 FILE *soubor /*save*/ : 127–128 void save_start(): 127, 160–161 char chyba /*save*/ : 127–128, 131, 135, 139–141, 156–157, 159–160
127
28 Moduly save a load 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: }
Program kraluk
if(!soubor){ warning("soubor %s nemohl byt otevren pro zapis", filename); chyba = 1; } byte = 0; bpos = 0; for(i = 0; i < CSL; i++) cs1[i] = 0; for(i = 0; i < CSL+1; i++) cs2[i] = 0; cs1pos = 0; cs2pos = 0;
Do tohoto souboru je ukládáno pomocí funkce save_bit, o kterou se opírají všechny další funkce, které něco ukládají. Tato funkce používá statické proměnné byte a bpos. Proměnná byte slouží jako úložiště uložených bytů než jich bude dost na to, aby se daly zapsat do souboru. Proměnná bpos určuje, do kterého bitu v proměnné byte bylo naposledy zapsáno. Tato proměnná se posunuje od sedmi do nuly, přičemž 7 je bit nejvíce vlevo a 0 bit nejvíce vpravo. JEDNA je definováno jako byte, který má pouze jeden jedničkový bit, který je nejvíce vpravo. Nejsem si totiž jistý, že to číslo 1 vždy splňuje. save.h 2: #define CSL 6 save.c 40: static unsigned char byte; 41: static char bpos; save.c 147: void save_bit (char b) 148: { 149: if(chyba) return; 150: 151: if(bpos == 0){ 152: bpos = 7; 153: byte = 0; 154: } 155: else bpos--; 156: 157: if(b) b=JEDNA; 158: byte |= b << bpos; 159: zapiscs(b, cs1, &cs1pos, CSL); 160: zapiscs(b, cs2, &cs2pos, CSL+1); 161: 162: if(bpos == 0) 163: if(fputc(byte, soubor) == EOF){ 164: chyba = 1; 165: warning("nemohl byt ulozen znak do souboru"); 166: } 167: }
Nakonec je třeba uložit poslední byte a uzavřít soubor, což dělá funkce save_end. save.c 91: void save_end () 92: { 93: if(!chyba && bpos){ 94: if(fputc(byte, soubor) == EOF){ 95: warning("nemohl byt ulozen zbyvajici byte"); 96: chyba = 1; 97: } 98: } 99: if(soubor) fclose(soubor); 100: }
Podobně funguje i načítání souboru. Funkce load_start otevře soubor do proměnné soubor a připraví i další proměnné. Proměnná chyba má opět stejnou funkci jako v modulu save, tedy upozornit funkce na to, že něco není v pořádku (například se nepodařilo načíst soubor). void save_bit(): 128, 130–134, 136, 140–142, 155–156, 161 unsigned char byte /*save*/ : 128 char bpos /*save*/ : 128 JEDNA: 128–129, 134 void save_end(): 128, 160–161 void load_start(): 129, 160–161 FILE *soubor /*load*/ : 129–130, 160–161 char chyba /*load*/ : 129–130, 135, 144–146, 150–157, 159–162
128
28 Moduly save a load
Program kraluk load.c
37: static FILE *soubor; 38: static char chyba; load.c 47: void load_start (char *filename) 48: { 49: int i; 50: 51: chyba = 0; 52: soubor = homefopen(filename, "r"); 53: 54: if(!soubor){ 55: chyba = 1; 56: return; 57: } 58: bpos = 0; 59: for(i = 0; i < CSL; i++) cs1[i] = 0; 60: for(i = 0; i < CSL+1; i++) cs2[i] = 0; 61: cs1pos = 0; 62: cs2pos = 0; 63: }
Funkcí load_bit jsou z tohoto souboru čteny bity. Tato funkce podle toho vrátí jedničku nebo nulu. Opět k tomu využívá proměnnou byte, do které si vždy načte znak ze souboru a pak z ní čte bity. Pro určení, který bit má být načten, je zde opět proměnná bpos. load.c 42: static unsigned char byte; 43: static char bpos; load.c 127: char load_bit () 128: { 129: char vysledek; 130: int ch; 131: 132: if(chyba) return 0; 133: 134: if(bpos == 0){ 135: bpos = 7; 136: ch = fgetc(soubor); 137: if(ch == EOF){ 138: chyba = 1; 139: warning("prilis brzky konec souboru"); 140: return 0; 141: } 142: byte = ch; 143: } 144: else bpos--; 145: 146: vysledek = (JEDNA << bpos) & byte; 147: if(vysledek) vysledek = 1; 148: zapiscs(vysledek, cs1, &cs1pos, CSL); 149: zapiscs(vysledek, cs2, &cs2pos, CSL+1); 150: return vysledek; 151: }
Nakonec se zkontroluje, jestli v souboru něco nezbylo a soubor se zavře. To provede funkce (kdo by to čekal) load_end. Tato funkce navíc opět může dostat v parametru název loadovaného souboru. Pokud ho dostane, touchne daný soubor, tedy zaktualizuje čas modifikace. Toto není provedeno, pokud načítání skončilo chybou nebo je parametrem NULL. load.c 67: void load_end (char *filename) 68: { 69: char *fullname; 70: char load_bit(): 129–130, 132–134, 136, 150–154, 157, 162 char byte /*load*/ : 129–130 char bpos /*load*/ : 129–130 void load_end(): 129, 160, 162
129
28 Moduly save a load 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: }
Program kraluk
if(!soubor) return; if(!chyba && fgetc(soubor) != EOF){ warning("pozde ukonceny soubor"); chyba = 1; } if(!chyba && (bpos && (unsigned char)(byte << (8-bpos)))){ warning("nevyprazdneny posledni byte"); chyba = 1; } if(!chyba && filename){ fullname = joinstrings(homedir, "/", filename, NULL); if(utime(fullname, NULL) == -1) warning("nepodarilo se touchnout %s", fullname); free(fullname); } if(soubor) fclose(soubor);
Program by měl číst pouze takové soubory, které si sám vytvořil, takže si do něj ukádá kontrolní součty. Při ukládání/načítání bitů jsou počítány kontrolní součty a nakonec je možné tyto součty uložit/zkontrolovat funkcí save_cs/check_cs. Po tom se dají opět ukládat/načítat další informace, ale ty už nejsou zahrnuty v tomto kontrolním součtu. Je však možné uložit/zkontrolovat další kontrolní součet. Pro počítání kontrolních součtů zde je funkce zapiscs. Tato funkce je velmi obecná. Dostane pole (parametr cs) o určité délce (parametr delka), ukazatel na index do tohoto pole (parametr cspos) a parametr co. Pak dané místo v poli vyxoruje s parametrem co a posune index do pole o jedničku. save.c 60: void zapiscs (char co, char *cs, int *cspos, int delka) 61: { 62: cs[*cspos] ^= co; 63: 64: (*cspos)++; 65: if(*cspos == delka) *cspos = 0; 66: }
Ve funkci save_bit a load_bit se funkce zapis_cs zavolá dvakrát. Jednou na pole cs1 o délce CSL, tedy 6, a index cs1pos a podruhé na pole cs2 o délce CSL+1, tedy 7, a index cs2pos. Vznikají tedy dva v podstatě nezávislé kontrolní součty. Kontrola, kontrolního součtu je jednoduchá. Funkce check_cs přečte CSL*2, tedy 12 bitů a pak zkontroluje, zda jsou obě pole vynulována. save.h 2: #define CSL 6 load.c 32: static char cs1[CSL], cs2[CSL+1]; 33: static int cs1pos, cs2pos; load.c 109: void check_cs () 110: { 111: int i; 112: 113: if(chyba) return; 114: 115: for(i=0; i
void zapiscs(): 128–130 char *cs1 /*save*/ : 128, 131 char *cs1 /*load*/ : 129–130 int cs1pos /*save*/ : 128, 131 int cs1pos /*load*/ : 129–130 char *cs2 /*save*/ : 128, 131 char *cs2 /*load*/ : 129–130 int cs2pos /*save*/ : 128, 131 int cs2pos /*load*/ : 129–130 void check_cs(): 130, 144, 160, 162 CSL: 128–131
130
28 Moduly save a load
Program kraluk
123: }
Uložit těchto 12 bitů už je složitější. Dělá to funkce save_cs. Pro demonstraci daného algoritmu použiji následující obrázek.
Výsledné pole je pole oněch dvanácti bitů, které chci uložit. Uložím si do lokální proměnné ch nulu a jdu podle šipek. Když projdu bílým políčkem, vyxoruji ch s hodnotou v tom políčku a když projdu světle modrým políčkem, tak tam ch zapíšu. Na konci bude ch opět nulové, protože počet všech jedniček v obou kontrolních polích (cs1 a cs2) je sudý. Čísla pod bílými políčky jsou indexy těchto polí za situace, kdy cs1pos = 2 a cs2pos = 6. save.c 35: static char cs1[CSL], cs2[CSL+1]; 36: static int cs1pos, cs2pos; save.c 119: void save_cs () 120: { 121: int i; 122: char checksum[CSL*2]; 123: char ch; 124: 125: if(chyba) return; 126: 127: i = -1; 128: for(ch = 0; i < CSL-1; checksum[i] = ch){ 129: i += CSL+1; 130: ch ^= cs2[(i+cs2pos)%(CSL+1)]; 131: checksum[i] = ch; 132: i -= CSL; 133: ch ^= cs1[(i+cs1pos)%(CSL)]; 134: } 135: 136: for(i=0; i
Kromě bitů je dobré umět ukládat i jiné datové typy. První datový typ, který vysvětlím, je trit, který se dá uložit funkcí save_trit a pak načíst funkcí load_trit. Trit je něco podobného jako bit, ale může to nabývat tří hodnot: Záporná, nulová a kladná. Pokud je nulová, bude do souboru uložen bit 0, pokud je hodnota kladná, jsou do souboru uloženy bity 10 a funkce load_trit pak vrátí jedničku. Když je void save_cs /*save*/ (): 130–131, 139, 160 void save_trit(): 132, 140–142, 155–156, 158 char load_trit(): 131–132, 150–151, 153–154, 157, 159
131
28 Moduly save a load
Program kraluk
záporná, jsou do souboru uloženy bity 11 a funkce load_trit vrátí minus jedničku. Tato funkce je dobrá pro ukládání hodnot položky lokalni ve strukturách kq_timer, kq_widget, kq_submap a kq_post. save.c 171: void save_trit (char t) 172: { 173: save_bit(t); 174: if(t){ 175: if(t > 0) save_bit(0); 176: else save_bit(1); 177: } 178: } load.c 155: char load_trit () 156: { 157: char vysledek; 158: 159: vysledek = load_bit(); 160: if(vysledek){ 161: if(load_bit()) vysledek = -1; 162: } 163: return vysledek; 164: }
Funkce save_unsint uloží nezáporné číslo, které se pak dá přečíst funkcí load_unsint. Toto číslo může být teoreticky libovolně veliké, pokud by takto veliký mohl být i datový typ unsigned int. Číslo je převedeno do trojkové soustavy s číslicemi 1, 2 a 3. Příklady čísel takových čísel: 0 1 2 3
= = = =
"" "1" "2" "3"
4 5 6 7
= = = =
"11" "12" "13" "21"
8 9 10 11
= = = =
"22" "23" "31" "32"
12 13 14 15
= = = =
"33" "111" "112" "113"
Tuto posloupnost číslic zakončím nulou a každou cifru uložím pomocí dvou bitů: 0 = 00, 1 = 01, 2 = 10, 3 = 11. save.c 192: void save_unsint (unsigned int i) 193: { 194: char dibit; 195: 196: // printf(" save_unsint(%d)\n", i); 197: 198: while(i){ 199: dibit = i%3; 200: if(!dibit) dibit = 3; 201: save_bit(dibit/2); 202: save_bit(dibit%2); 203: i -= dibit; 204: i /= 3; 205: } 206: save_bit(0); save_bit(0); 207: } load.c 181: unsigned int load_unsint () 182: { 183: int vysledek, mocnina; 184: char dibit; 185: 186: vysledek = 0; 187: 188: for(mocnina = 1;; mocnina *= 3){ 189: dibit = 2*load_bit(); 190: dibit += load_bit(); 191: if(!dibit) break; 192: vysledek += dibit*mocnina; void save_unsint(): 118, 132–133, 135, 137–143, 161 144, 151, 153–155, 161–162
132
unsigned int load_unsint(): 132–133, 135,
28 Moduly save a load
Program kraluk
193: } 194: 195: // printf(" load_unsint(%d)\n", vysledek); 196: 197: return vysledek; 198: }
Když už umím uložit nezáporné číslo, není problém uložit celé číslo. Jednoduše si do prvního bitu uložím, jestli je toto číslo záporné. Celá čísla ukládám pomocí funkce save_int. save.c 211: void save_int (int i) 212: { 213: if(i < 0){ 214: save_bit(1); 215: i = -i-1; 216: } 217: else save_bit(0); 218: 219: save_unsint(i); 220: }
Potom je možné celé číslo opět přečíst pomocí funkce load_int. load.c 202: int load_int () 203: { 204: if(load_bit()) return -load_unsint()-1; 205: else return load_unsint(); 206: }
Kromě libovolně velkého čísla mohu ukládat i čísla, o kterých vím, že jsou v určitém rozsahu (a budu to vědět i při načítání). Řeší to funkce save_intoddo, která kromě prvního parametru čísla, které chci uložit, dostane druhý parametr (nejnižší možné číslo) a třetí parametr (nejvyšší možné číslo). Tato funkce funguje na principu půlení intervalů. Rozpůlí interval, který dostane a pak zavolá sama sebe na interval, kde se ukládané číslo nalézá. Těsně předtím uloží do souboru bit o tom, který interval si vybrala. Tato rekurze skončí v okamžiku, kdy interval obsahuje už jen jedno číslo, tedy to, které má být uloženo. Pravda místo rekurze by stačilo použít jednoduchý cyklus či goto konstrukci, takhle se mi to však jeví nejpřehlednější. save.c 224: void save_intoddo (int i, int prvni, int posledni) 225: { 226: int j; 227: 228: if(prvni > posledni){ 229: warning("interval <%d; %d> ma spatne usporadane hodnoty", prvni, posledni); 230: j = prvni; 231: prvni = posledni; 232: posledni = j; 233: } 234: if(i < prvni){ 235: warning("cislo %d je mimo interval <%d; %d>", i, prvni, posledni); 236: i = prvni; 237: } 238: else if(posledni < i){ 239: warning("cislo %d je mimo interval <%d; %d>", i, prvni, posledni); 240: i = posledni; 241: } 242: 243: if(prvni == posledni) return; 244: 245: j = (prvni + posledni + 1)/2; 246: if(i < j){ 247: save_bit(0); 248: save_intoddo(i, prvni, j-1); 249: } void save_int(): 133, 136, 139–142, 155–156, 158 void save_intoddo: 133–134, 136–138, 143, 158, 161
133
int load_int(): 133, 136, 149–154, 157, 159
28 Moduly save a load
Program kraluk
250: else{ 251: save_bit(1); 252: save_intoddo(i, j, posledni); 253: } 254: }
Takto uložené číslo se dá přečíst funkcí load_intoddo. Tato funkce musí dostat stejné parametry, jako byly dány funkci save_intoddo kromě prvního, tedy ukládaného čísla. Toto ukládané číslo vrátí jako návratovou hodnotu. Funguje na stejném principu jako ukládací funkce. Rozpůlí interval, přečte si, kterou půlku si má vybrat, a zavolá sama sebe. Jakmile interval obsahuje už jen jeden člen, tedy jeho krajní body se shodují, je vrácena hodnota krajních bodů. load.c 210: int load_intoddo (int prvni, int posledni) 211: { 212: int j; 213: 214: if(prvni > posledni){ 215: warning("interval <%d; %d> ma spatne usporadane hodnoty", prvni, posledni); 216: j = prvni; 217: prvni = posledni; 218: posledni = j; 219: } 220: 221: if(prvni == posledni) return prvni; 222: 223: j = (prvni + posledni + 1)/2; 224: 225: if(load_bit() == 0){ 226: return load_intoddo(prvni, j-1); 227: } 228: else{ 229: return load_intoddo(j, posledni); 230: } 231: }
Dále umím pomocí funkce save_char ukládat znaky. Tento znak je ukládán po bitech, takže šance, že bude tento znak zobrazen v textovém editoru správně je 18 . save.c 182: void save_char (char ch) 183: { 184: char pos; 185: 186: for(pos = 7; pos >= 0; pos--) 187: save_bit((JEDNA<<pos) & ch); 188: }
Takto uložený znak se pak samozřejmě dá přečíst funkcí load_char. load.c 168: char load_char () 169: { 170: char pos, vysledek; 171: 172: vysledek = 0; 173: for(pos = 7; pos >= 0; pos--) 174: if(load_bit()) 175: vysledek |= JEDNA << pos; 176: return vysledek; 177: }
Nyní přecházím k další kontrolní funkci a to je funkce check_idstr, která zkontroluje identifikační string. To je string, který je uložen v proměnné ident_str. Pokud tam žádný string uložen není, funkce check_idstr nedělá nic.
int load_intoddo(): 134, 150–155, 159, 162 void save_char(): 118, 134–135, 155–156 load_char(): 134–135, 157, 162 void check_idstr(): 134–135, 160
134
28 Moduly save a load
Program kraluk
Jinak postupně čte znaky ze souboru a kontroluje je se znaky ve stringu ident_str včetně znaku 0. Pokud se nějaký znak neshoduje, nastaví proměnnou chyba na true, takže soubor nebude načten. Já tuto funkci spouštím na začátku načítání ze souboru, ale je možné ji spustit kdykoliv. load.c 92: void check_idstr () 93: { 94: int i; 95: 96: if(!identstring || chyba) return; 97: for(i=0;; i++){ 98: if(load_char() != identstring[i]){ 99: warning("nesouhlasi identifikacni string"); 100: chyba = 1; 101: return; 102: } 103: if(identstring[i] == 0) break; 104: } 105: }
Pro uložení identifikačního stringu ident_str do souboru slouží funkce save_idstr save.c 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115:
char *identstring = NULL; void save_idstr () { int i; if(!identstring || chyba) return; for(i=0;; i++){ save_char(identstring[i]); if(identstring[i] == 0) return; } }
Také mohu uložit libovolný jiný string funkcí save_string. Tato funkce ukládá string v jiném formátu než funkce save_idstr. Nejprve uloží délku stringu a pak jeho znaky. Není ukládán koncový byte 0. save.c 258: void save_string (char *str) 259: { 260: int i; 261: 262: save_unsint(strlen(str)); 263: for(i=0; str[i]; i++) save_char(str[i]); 264: }
V tomto formátu je string ukládán proto, aby načítací funkce load_string si mohla hned na začátku naalokovat pole příslušné délky. load.c 235: char *load_string () 236: { 237: unsigned int delka, i; 238: char *vysledek; 239: 240: if(chyba) return NULL; 241: 242: delka = load_unsint(); 243: vysledek = (char *)malloc(sizeof(char)*(delka+1)); 244: if(vysledek){ 245: for(i=0; i<delka && !chyba; i++) vysledek[i] = load_char(); 246: vysledek[delka] = 0; 247: } 248: else{ 249: chyba = 1; 250: warning("load: malloc vratil NULL"); char *ident_str: 134–135 void save_idstr(): 135, 160 char *load_string(): 135, 150–151, 153, 162
135
void save_string(): 135, 140–142, 161
28 Moduly save a load
Program kraluk
251: } 252: 253: return vysledek; 254: }
Další datový typ, který mohu uložit, je float. Ten však mohu uložit jen s určitými omezeními: 1) Uložím maximálně 3 desetinná místa. 2) Neuložím číslo, které se nevejde do intu. Typ float se ukládá funkcí save_float. Nejprve se uloží pomocí dvou bitů počet desetinných míst (i ∈ h0; 3i), pak se ukládané číslo vynásobí číslem 10i a uloží se jako celé číslo. save.c 268: void save_float (float f) 269: { 270: int i, j; 271: float g; 272: 273: j=1; 274: g=f; 275: for(i=0; (int)g != g && i<3; i++){ 276: j *= 10; 277: g = j*f; 278: } 279: save_int((int)g); 280: save_bit(i/2); 281: save_bit(i%2); 282: }
Načíst float pak mohu funkcí load_float. load.c 258: float load_float () 259: { 260: float vysledek; 261: int j; 262: 263: j=1; 264: vysledek = load_int(); 265: if(load_bit()) j *= 100; 266: if(load_bit()) j *= 10; 267: vysledek /= j; 268: 269: return vysledek; 270: }
28.2
Ukládání vnitřních struktur
Zde řeším dvě věci. Za prvé, jak uložit pointer na nějakou strukturu jak uložit všechny pixmapy, widgety, submapy, timery, postavy a animace postavy. První problém řeším pomocí položky Cislo, která je ve strukturách: kq_pixmap, kq_widget, kq_submap, kq_animpost, kq_postava, kq_timer a kq_policko. Hodnotu položky Cislo tedy jednoduše uložím do souboru pomocí funkce save_intoddo. Číslo 0 je rezervováno pro pointer NULL, kladná čísla určují pořadí tohoto pointeru ve standartním seznamu této struktury a záporná čísla pro nějaký jiný seznam stejného typu (schované timery, zapausované timery a schované submapy, zafixované pixmapy a zafixované animace postavy). Pořadí některých struktur se však v průběhu hry mění a není jednoduché je stále udržovat aktuální. V takových struktuách nastavím položku Cislo pouze na začátku ukládání do souboru, tedy ve funkci save_pocty. Pouze pro políčka a zafixované struktury není třeba toto pořadí počítat. Ve funkci save_pocty také spočítám počty jednotlivých struktur a uložím to do globálních statických proměnných začínajících na pocet_. Počty struktur, které se v průběhu hry nemění, zde počítány nejsou a počítají se už při vytváření (pocet_fixpix, pocet_pol, pocet_fixanip a pocet_func). void save_float(): 136, 140, 142, 155–156 float *load_float(): 136, 150–151, 153–154, 157 Cislo: 27, 35, 37, 44, 56, 63, 70, 74, 86–88, 136–139, 168, 170–171, 181
136
28 Moduly save a load
Program kraluk
Další výjimkou jsou barvy, kde položka číslo vůbec není a je tedy třeba projít celý seznam aktuálních barev, tedy těch, které jsou buď globální nebo jsou lokální v aktuálním políčku. Procházím to proto, abych zjistil, zda podávaná barva je aktuální. Funkce, která uloží pointer na barvu, se jmenuje save_color. save.c 345: void save_color (kq_color *c) 346: { 347: unsigned int i; 348: kq_color *pom; 349: 350: if(c == NULL){ 351: save_unsint(0); 352: return; 353: } 354: 355: i = 1; 356: for(pom = prvbarva; pom && pom != c; pom = pom->next) i++; 357: if(!pom){ 358: warning("barva nenalezena"); 359: i = 0; 360: } 361: save_unsint(i); 362: }
Struktura animwid nemá položku Cislo. Předpokládám, že každý ukazatel na tuto strukturu je ukazatelem do pole animpole. Celá funkce save_awid je v podstatě jen pro ukládání timerů s funkcí animuj. save.c 734: void save_awid (kq_anim *anim) 735: { 736: save_intoddo(anim-animpole, 0, aktupol->pocetanim-1); 737: }
Další funkce, které ukládají pointer jsou dost podobné: Uložení pointeru na slovo: save.c 495: void save_word (kq_word *w) 496: { 497: if(!w) save_intoddo(0, 0, pocet_word); 498: else save_intoddo(w->Cislo, 0, pocet_word); 499: }
Uložení pointeru na pixmapu: save.c 515: void save_pixmap (kq_pixmap *pxm) 516: { 517: if(!pxm) save_intoddo(0, pocet_fixpix, pocet_pix); 518: else save_intoddo(pxm->Cislo, pocet_fixpix, pocet_pix); 519: }
Uložení pointeru na widget: save.c 544: void save_widget (kq_widget *w) 545: { 546: if(w) save_intoddo(w->Cislo, pocet_hwid, pocet_wid); 547: else save_intoddo(0, pocet_hwid, pocet_wid); 548: }
Uložení pointeru na submapu: save.c 575: void save_submap (kq_submap *sm) 576: { 577: if(sm == NULL) save_intoddo(0, pocet_hsm, pocet_sm); 578: else save_intoddo(sm->Cislo, pocet_hsm, pocet_sm); void save_color(): 137, 155, 157 void save_awid(): 137, 155, 157 void save_word(): 142, 149, 155, 157 void save_pixmap(): 140–141, 143, 150, 155, 157 void save_widget(): 142–143, 150, 155, 157 void save_submap(): 140, 142, 151, 155, 157
137
28 Moduly save a load
Program kraluk
579: }
Uložení pointeru na animaci postavy: save.c 611: void save_anip (kq_animpost *anip) 612: { 613: if(anip == NULL) save_intoddo(0, pocet_fixanip, pocet_anip); 614: else save_intoddo(anip->Cislo, pocet_fixanip, pocet_anip); 615: }
Uložení pointeru na postavu: save.c 671: void save_post (kq_postava *post) 672: { 673: if(post == NULL) save_intoddo(0, 0, pocet_post); 674: else save_intoddo(post->Cislo, 0, pocet_post); 675: }
Uložení pointeru na předmět: save.c 709: void save_predmet (kq_predmet *p) 710: { 711: if(!p) save_intoddo(0, 0, pocet_predm); 712: else save_intoddo(p->Cislo, 0, pocet_predm); 713: }
Uložení pointeru na timer: save.c 764: void save_timer (kq_timer *tim) 765: { 766: if(tim == NULL) save_intoddo(0, pocet_ptim, pocet_tim); 767: else save_intoddo(tim->Cislo, pocet_ptim, pocet_tim); 768: }
Uložení pointeru na políčko: save.c 772: void save_pol (kq_policko *pol) 773: { 774: if(!pol) save_intoddo(0, 0, pocet_pol); 775: else save_intoddo(pol->Cislo, 0, pocet_pol); 776: }
Tím bych měl vyřešený první problém a jdu řešit ukládání samotných struktur. Funkce, která by měla být zavolána před načítáním všech možných struktur či pointerů na ně, tedy save_pocty, udělá následující operace: • Zapíše do položky Cislo všech možných vnitřních astruktur její pořadí. • Spočítá počty pixmap, widgetů, schovaných widgetů, . . . a uloží je do globálních statických proměnných začínajících na pocet_ Pokud počítá seznam, který používá zápornou položku Cislo, bude i odpovídající proměnná záporná. • Tyto počty uloží do souboru pomocí funkce save_unsint • Uloží aktuální políčko • Nakonec uloží kontrolní součet. save.c 286: static int pocet_pix, pocet_wid, pocet_hwid, pocet_sm, pocet_hsm, 287: pocet_anip, pocet_post, pocet_tim, pocet_ptim, pocet_predm; 288: 289: void save_pocty () 290: { 291: kq_pixmap *ppom; void save_anip(): 142, 152, 155, 157 void save_post(): 142, 153, 155, 157 void save_predmet(): 153, 155, 157 void save_timer(): 141–143, 154–155, 157 void save_pol(): 139, 142, 154–155, 157 void save_pocty: 136, 138, 140, 160 int pocet_pix /*save*/ : 137–139 int pocet_wid /*save*/ : 137–139 int pocet_hwid /*save*/ : 137–139 int pocet_sm /*save*/ : 137–139 int pocet_hsm /*save*/ : 137–139 int pocet_anip /*save*/ : 138–139 int pocet_post /*save*/ : 138–139 int pocet_tim /*save*/ : 138–139 int pocet_ptim /*save*/ : 138–139
138
28 Moduly save a load 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: }
Program kraluk
kq_widget *wpom; kq_submap *smpom; kq_animpost *appom; kq_postava *popom; kq_timer *tpom; kq_predmet *prpom; int i; pocet_pix = pocet_wid = pocet_hwid = pocet_sm = pocet_hsm = pocet_anip = pocet_post = pocet_predm = pocet_tim = pocet_ptim = 0; if(chyba) return; for(ppom = prvpix; ppom; ppom = ppom->next) ppom->Cislo = ++pocet_pix; save_unsint(pocet_pix); // pixmapy for(wpom = prvwidget; wpom; wpom = wpom->next) wpom->Cislo = ++pocet_wid; save_unsint(pocet_wid); // widgety for(wpom = poshidwid; wpom; wpom = wpom->prev) wpom->Cislo = --pocet_hwid; save_unsint(-pocet_hwid); // schovane widgety for(smpom = prvsubmap; smpom; smpom = smpom->next) smpom->Cislo = ++pocet_sm; save_unsint(pocet_sm); // submapy for(smpom = prvhidsm; smpom; smpom = smpom->next) smpom->Cislo = --pocet_hsm; save_unsint(-pocet_hsm); // schovane submapy for(appom = prvanip; appom; appom = appom->next) appom->Cislo = ++pocet_anip; save_unsint(pocet_anip); // animace postav for(popom = prvpost; popom; popom = popom->next) popom->Cislo = ++pocet_post; save_unsint(pocet_post); // postavy for(tpom = prvtimer; tpom; tpom = tpom->next) tpom->Cislo = ++pocet_tim; save_unsint(pocet_tim); // timery for(tpom = pausedtimers; tpom; tpom = tpom->next) tpom->Cislo = --pocet_ptim; save_unsint(-pocet_ptim); // zapausovane timery if(aktutimer) aktutimer->Cislo = 0; for(prpom = prvpredmet; prpom; prpom = prpom->next) prpom->Cislo = ++pocet_predm; save_unsint(pocet_predm); save_pol(aktupol); for(i=0; ipocetanim; i++) save_unsint(animpole[i].pocet); save_cs();
Nezávislá na funkci save˙pocty je jen funkce save_kontexts. Tato funkce projde všechna slova a uloží do souboru bit, zda je toto slovo právě v kontextu save.c 485: void save_kontexts () 486: { 487: kq_word *pom; 488: 489: for(pom = prvulslovo; pom; pom = pom->next) 490: save_int(pom->kontext); 491: }
Při ukládání dat ve widgetech požívám pomocnou funkci save_winfo, která uloží data z jednoho widgetu. Tato funkce neuloží položku hide, protože její hodnota je jasná už z toho, v jakém seznamu se nachází. void save_kontexts(): 139, 149, 160
void save_winfo(): 140, 150
139
28 Moduly save a load
Program kraluk save.c
523: void save_winfo (kq_widget *w) 524: { 525: save_pixmap(w->obr); 526: save_int(w->x); 527: save_int(w->y); 528: save_float(w->z); 529: save_trit(w->lokalni); 530: }
Ve funkci save_widgets, která má widgety uložit, projdu všechny widgety a zavolám na ně funci savewinfo. save.c
534: void save_widgets () 535: { 536: kq_widget *pom; 537: 538: for(pom = prvwidget; !chyba && pom; pom = pom->next) save_winfo(pom); 539: for(pom = poshidwid; !chyba && pom; pom = pom->prev) save_winfo(pom); 540: }
Podobně pro ukládání dat v submapě mám funkci save_sminfo. Při ukládání submapy neuložím její pixely, ale jen název souboru, ze kterého byla načtena. Stejně jako u widgetů neuložím položku hide. save.c 552: void save_sminfo (kq_submap *sm) 553: { 554: save_string(sm->nazev); 555: save_int(sm->x); 556: save_int(sm->y); 557: save_float(sm->z); 558: save_trit(sm->lokalni); 559: }
Funkce save_submaps projde všechny submapy a zavolá na ně funkci save_sminfo. Kromě toho uloží pointer na bgmap. save.c 563: void save_submaps () 564: { 565: kq_submap *pom; 566: 567: if(chyba) return; 568: save_submap(bgmap); 569: for(pom = prvsubmap; pom; pom = pom->next) save_sminfo(pom); 570: for(pom = prvhidsm; pom; pom = pom->next) save_sminfo(pom); 571: }
Takovým způsobem ukládám i timery. Funkcí save_tinfo uložím data v jednom timeru. Stejně jako u widgetů a submap neukládám položku hide. save.c 741: void save_tinfo (kq_timer *tim) 742: { 743: save_func(tim->funkce, &tim->parametr); 744: save_unsint(tim->zbyva); 745: save_float(tim->priorita); 746: save_int(tim->opakovani); 747: save_unsint(tim->cas); 748: save_bit(tim->pause); 749: save_trit(tim->lokalni); 750: }
A funkcí save_timers projdu všechny timery a uložím je funkcí save_tinfo. Neuložím ovšem timer aktutimer, protože se domnívám, že je zde poněkud nepodstatný. Ve funkci save_pocty dostal aktutimer přiděleno číslo 0, takže bude pointer na něj ukládán stejně jako NULL.
void save_widgets(): 140, 150, 160 void save_sminfo(): 140, 151 void save_submaps(): 140, 151, 160 void save_tinfo(): 140–141, 154 void save_timers(): 141, 154, 160
140
28 Moduly save a load
Program kraluk save.c
754: void save_timers () 755: { 756: kq_timer *pom; 757: 758: for(pom = prvtimer; !chyba && pom; pom = pom->next) save_tinfo(pom); 759: for(pom = pausedtimers; !chyba && pom; pom = pom->next) save_tinfo(pom); 760: }
V dalších funkcích již nebudu potřebovat funkci, která uloží data z jedné položky, protože už vše uložim v jednom cyklu. Při ukládání pixmap funkcí save_pixmaps, stejně jako u submap, ukládám pouze název souboru, ze kterého byla načtena a ne samotné pixely. save.c 503: void save_pixmaps () 504: { 505: kq_pixmap *pom; 506: 507: for(pom = prvpix; !chyba && pom; pom = pom->next){ 508: save_bit(pom->lokalni); 509: save_string(pom->nazev); 510: } 511: }
Ukládání animací postav: save.c 583: void save_anips () 584: { 585: kq_animpost *pom; 586: 587: int pocetpix, i; 588: 589: for(pom = prvanip; !chyba && pom; pom = pom->next){ 590: save_int(pom->x); 591: save_int(pom->y); 592: save_unsint(pom->framu); 593: save_unsint(pom->tim); 594: save_trit(pom->jednopol); 595: save_bit(pom->porad); 596: save_bit(pom->lokalni); 597: 598: pocetpix = pom->framu; 599: if(!pom->jednopol) pocetpix *= 4; 600: if(pocetpix < 1){ 601: chyba = 1; 602: warning("mene nez jedna (%d) pixmapa v animaci postavy", pocetpix); 603: } 604: else if(pocetpix == 1) save_pixmap(pom->pix.map); 605: else for(i = 0; i < pocetpix; i++) save_pixmap(pom->pix.pole[i]); 606: } 607: }
Ukládání postav: save.c 619: void save_posts () 620: { 621: kq_postava *pom; 622: 623: for(pom = prvpost; !chyba && pom; pom = pom->next){ 624: save_int(pom->x); 625: save_int(pom->y); 626: save_int(pom->xx); 627: save_int(pom->yy); 628: save_timer(pom->tim); 629: save_bit(pom->zdi); 630: save_bit(pom->barvy);
void save_pixmaps(): 141, 150, 160
void save_anips(): 151, 160
141
void save_posts(): 152, 160
28 Moduly save a load 631: 632: 633: 634: 635: 636: 637: 638: 639: 640: 641: 642: 643: 644: 645: 646: 647: 648: 649: 650: 651: 652: 653: 654: 655: 656: 657: 658: 659: 660: 661: 662: 663: 664: 665: 666: } 667: }
Program kraluk
save_bit(pom->odraz); save_bit(pom->odejde); save_submap(pom->submap); save_int(pom->sm_x); save_int(pom->sm_y); save_int(pom->chyt_vzdal); save_func(pom->chyt_func, NULL); save_func(pom->auto_func, NULL); save_func(pom->free_func, NULL); if(pom->autou_typ == AUTOU_SOUR){ save_bit(0); save_int(pom->auto_u.sourad.x); save_int(pom->auto_u.sourad.y); } else{ save_bit(1); save_post(pom->auto_u.sledpost); } save_timer(pom->auto_tim); save_anip(pom->animace); save_unsint(pom->smer); save_unsint(pom->animstav); save_timer(pom->animtim); save_float(pom->xz); save_float(pom->yz); save_float(pom->z); save_widget(pom->widget); save_trit(pom->lokalni); save_bit(pom->hide); save_bit(pom->zmena);
Ukládání předmětů: save.c 679: void save_predmets () 680: { 681: kq_predmet *pom; 682: int i; 683: 684: for(pom = inventar; pom; pom = pom->polnext) i++; 685: for(pom = inventar; pom; pom = pom->polnext) pom->inv = i--; 686: 687: for(pom = prvpredmet; pom; pom = pom->next){ 688: save_word(pom->slovo); 689: save_string(pom->nazev); 690: save_unsint(pom->inv); 691: save_bit(pom->stav); 692: save_post(pom->post); 693: if(!pom->inv){ 694: save_pol(pom->pol); 695: if(pom->pol){ 696: save_int (pom->pix_x); 697: save_int (pom->pix_y); 698: save_float(pom->pix_z); 699: save_int (pom->sm_x); 700: save_int (pom->sm_y); 701: save_float(pom->sm_z); 702: } 703: } 704: } void save_predmets(): 153, 160
142
28 Moduly save a load
Program kraluk
705: }
Ukládání animací políčka: save.c 717: void save_awids () 718: { 719: int i, j; 720: 721: for(i=0; ipocetanim; i++){ 722: save_intoddo(animpole[i].faze, 0, animpole[i].pocet); 723: save_widget(animpole[i].widget); 724: save_timer(animpole[i].timer); 725: for(j=0; j
28.3
Načítání vnitřních struktur
Načítání, podobně jaku ukládání, začíná funkcí load_pocty. Tato funkce si přečte ze souboru počty jednotlivých struktur a uloží je do statických proměnných začínající na pocet_. load.c 286: static int pocet_pix, pocet_wid, pocet_hwid, pocet_sm, pocet_hsm, 287: pocet_anip, pocet_post, pocet_tim, pocet_ptim, pocet_predm;
Také zjistí aktuální políčko. Potom zkontroluje kontrolní součet. A pak namallokuje zjištěný počet struktur. Kontrolní součet je zde kontrolován proto, aby kvůli vadnému souboru nemallocoval příliš. Přestože je kontrolní součet kontrolován už zde, nemohu si být jistý, že je tento soubor zcela v pořádku, a tak si nemohu dovolit ukládat načítané informace přímo do stávajících struktur a tím je přepsat. Místo toho tedy používám statické proměnné: 274: 275: 276: 277: 278: 279: 280: 281: 282:
static static static static static static static static static
kq_pixmap *loaded_pixmaps; kq_widget *loaded_widgets, *loaded_hidwids; kq_submap *loaded_submaps, *loaded_bgmap, *loaded_hidmaps; kq_animpost *loaded_anips; kq_postava *loaded_posts; kq_timer *loaded_timers, *loaded_pautims; kq_predmet *loaded_predmets; kq_policko *loaded_pol; kq_anim *loaded_apole;
// // // // // // // // //
load.c prvpix prvwidget, poshidwid prvsubmap, bgmap, prvhidsm prvanip prvpost prvtimer, pausedtimers prvpredmet aktupol animpole
Funkce load_pocty tedy vypadá takto: load.c 291: void load_pocty () 292: { 293: int i; 294: kq_pixmap *ppom; 295: kq_widget *wpom; 296: kq_submap *smpom; 297: kq_animpost *appom; 298: kq_postava *popom; 299: kq_timer *tpom; 300: kq_predmet *prpom; void save_awids(): 155, 160 int pocet_pix /*load*/ : 144, 150 int pocet_wid /*load*/ : 144, 151 int pocet_hwid /*load*/ : 144–145, 151 int pocet_sm /*load*/ : 144–145, 151 int pocet_hsm /*load*/ : 144–145, 151 int pocet_anip /*load*/ : 144–145, 152 int pocet_post /*load*/ : 144–145, 153 int pocet_tim /*load*/ : 144–145, 154 int pocet_ptim /*load*/ : 144, 146, 154 kq_pixmap *loaded_pixmaps /*load*/ : 144, 147–148, 150 kq_widget *loaded_widgets /*load*/ : 144–145, 147–148, 150–151 kq_widget *loaded_hidwids /*load*/ : 144–145, 147, 149–151 kq_submap *loaded_submaps /*load*/ : 144–145, 147, 149, 151 kq_submap *loaded_bgmap /*load*/ : 144, 147, 151 kq_submap *loaded_hidmap /*load*/ : 144–145, 147, 149, 151 kq_animpost *loaded_anips /*load*/ : 144–145, 148–149, 151–152 kq_postava *loaded_posts /*load*/ : 144–145, 148–149, 152–153 kq_timer *loaded_timers /*load*/ : 144, 146, 148–149, 154 kq_timer *loaded_pautims /*load*/ : 144, 146, 148–149, 154 kq_timer *loaded_predmets /*load*/ : 144, 146, 148–149, 153–154 kq_timer *loaded_pol kq_timer *loaded_apole /*load*/ : 144, 146–147, 149, 155 /*load*/ : 144, 146–147, 149, 155 void load_pocty(): 143, 160
143
28 Moduly save a load 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368:
Program kraluk
loaded_pixmaps = NULL; loaded_widgets = NULL; loaded_hidwids = NULL; loaded_submaps = NULL; loaded_hidmaps = NULL; loaded_bgmap = NULL; loaded_anips = NULL; loaded_posts = NULL; loaded_timers = NULL; loaded_pautims = NULL; loaded_predmets = NULL; loaded_apole = NULL; pocet_pix pocet_wid pocet_hwid pocet_sm pocet_hsm pocet_anip pocet_post pocet_tim pocet_ptim pocet_predm
= load_unsint(); = load_unsint(); = -load_unsint(); = load_unsint(); = -load_unsint(); = load_unsint(); = load_unsint(); = load_unsint(); = -load_unsint(); = load_unsint();
loaded_pol = load_pol(); if(chyba) return; if(loaded_pol){ loaded_apole = malloc(sizeof(kq_anim)*loaded_pol->pocetanim); if(!loaded_apole){ chyba = 1; warning("load: malloc vratil NULL"); return; } for(i=0; ipocetanim; i++){ loaded_apole[i].pocet = load_unsint(); loaded_apole[i].pix = NULL; loaded_apole[i].casy = NULL; } } check_cs(); if(chyba) return; for(i = 0; i < pocet_pix; i++){ ppom = (kq_pixmap *)malloc(sizeof(kq_pixmap)); if(!ppom){ chyba = 1; warning("load: malloc vratil NULL"); return; } ppom->nazev = NULL; ppom->next = loaded_pixmaps; loaded_pixmaps = ppom; } for(i = 0; i < pocet_wid; i++){ wpom = (kq_widget *)malloc(sizeof(kq_widget)); if(!wpom){ chyba = 1; warning("load: malloc vratil NULL"); return; } wpom->next = loaded_widgets; if(loaded_widgets) loaded_widgets->prev = wpom;
144
28 Moduly save a load 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436:
Program kraluk
loaded_widgets = wpom; } if(loaded_widgets) loaded_widgets->prev = NULL; for(i = 0; i > pocet_hwid; i--){ wpom = (kq_widget *)malloc(sizeof(kq_widget)); if(!wpom){ chyba = 1; warning("load: malloc vratil NULL"); return; } wpom->prev = loaded_hidwids; if(loaded_hidwids) loaded_hidwids->next = wpom; loaded_hidwids = wpom; } if(loaded_hidwids) loaded_hidwids->next = NULL; for(i=0; i < pocet_sm; i++){ smpom = (kq_submap *)malloc(sizeof(kq_submap)); if(!smpom){ chyba = 1; warning("load: malloc vratil NULL"); return; } smpom->nazev = NULL; smpom->next = loaded_submaps; loaded_submaps = smpom; } for(i=0; i > pocet_hsm; i--){ smpom = (kq_submap *)malloc(sizeof(kq_submap)); if(!smpom){ chyba = 1; warning("load: malloc vratil NULL"); return; } smpom->nazev = NULL; smpom->next = loaded_hidmaps; loaded_hidmaps = smpom; } for(i=0; i < pocet_anip; i++){ appom = (kq_animpost *)malloc(sizeof(kq_animpost)); if(!appom){ chyba = 1; warning("load: malloc vratil NULL"); return; } appom->pix.pole = NULL; appom->next = loaded_anips; loaded_anips = appom; } for(i=0; i < pocet_post; i++){ popom = (kq_postava *)malloc(sizeof(kq_postava)); if(!popom){ chyba = 1; warning("load: malloc vratil NULL"); return; } popom->next = loaded_posts; loaded_posts = popom; } for(i=0; i < pocet_tim; i++){ tpom = (kq_timer *)malloc(sizeof(kq_timer)); if(!tpom){ chyba = 1;
145
28 Moduly save a load 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: }
Program kraluk
warning("load: malloc vratil NULL"); return; } tpom->next = loaded_timers; loaded_timers = tpom; } for(i=0; i > pocet_ptim; i--){ tpom = (kq_timer *)malloc(sizeof(kq_timer)); if(!tpom){ chyba = 1; warning("load: malloc vratil NULL"); return; } tpom->next = loaded_pautims; loaded_pautims = tpom; } for(i=0; i < pocet_predm; i++){ prpom = (kq_predmet *)malloc(sizeof(kq_predmet)); if(!prpom){ chyba = 1; warning("load: malloc vratil NULL"); return; } prpom->nazev = NULL; prpom->next = loaded_predmets; loaded_predmets = prpom; } for(i=0; ipocetanim; i++){ loaded_apole[i].pix = malloc(loaded_apole[i].pocet*sizeof(kq_pixmap *)); if(!loaded_apole[i].pix){ chyba = 1; warning("load: malloc vratil NULL"); return; } loaded_apole[i].casy = malloc(loaded_apole[i].pocet*sizeof(unsigned int)); if(!loaded_apole[i].casy){ chyba = 1; warning("load: malloc vratil NULL"); return; } }
Po dokončení načítání se mohou stát dvě věci. Buď byl soubor načten v pořádku (chyba == 0) nebo nebyl (chyba == 1). Pokud byl načten v pořádku je třeba smazat původní struktury a nahradit je načtenými. To dělá funkce apply_load. load.c 1038: void apply_load () 1039: { 1040: kq_pixmap *ppom; 1041: kq_widget *wpom; 1042: kq_submap *smpom; 1043: sl_var *vpom; 1044: kq_word *wopom; 1045: kq_predmet *prpom, **prpomo; 1046: 1047: // Promenne: 1048: 1049: for(vpom = prvslvar; vpom; vpom = vpom->next){ 1050: if(vpom->typ == SL_CHAR || vpom->typ == SL_CHAR) 1051: *(char *)vpom->ukazatel = vpom->loaded.ch; 1052: else if(vpom->typ == SL_INT) *(int *)vpom->ukazatel = vpom->loaded.i; void apply_load(): 146, 149, 156, 160
146
28 Moduly save a load 1053: 1054: 1055: 1056: 1057: 1058: 1059: 1060: 1061: 1062: 1063: 1064: 1065: 1066: 1067: 1068: 1069: 1070: 1071: 1072: 1073: 1074: 1075: 1076: 1077: 1078: 1079: 1080: 1081: 1082: 1083: 1084: 1085: 1086: 1087: 1088: 1089: 1090: 1091: 1092: 1093: 1094: 1095: 1096: 1097: 1098: 1099: 1100: 1101: 1102: 1103: 1104: 1105: 1106: 1107: 1108: 1109: 1110: 1111: 1112: 1113: 1114: 1115: 1116: 1117: 1118: 1119: 1120:
Program kraluk
else if(vpom->typ == SL_FLOAT) *(int *)vpom->ukazatel = vpom->loaded.f; else *(void **)vpom->ukazatel = vpom->loaded.p; } // Kontexty slov: for(wopom = prvulslovo; wopom; wopom = wopom->next) wopom->kontext = wopom->loaded_kontext; // Pixmapy: deleteApixmaps(); prvpix = loaded_pixmaps; for(ppom = prvpix; ppom; ppom = ppom->next){ ppom->barvy = nactiXPM(ppom->nazev, &ppom->ibarvy, &ppom->akanal, &ppom->ikanal); ppom->scaled = ratio; } // Policko: if(win) free_animpole(); set_pol(loaded_pol); if(win) zmenokno(loaded_pol->jmpixmap); else vytvorokno(loaded_pol->jmpixmap); animpole = loaded_apole;
// Widgety: deleteAwidgets(); prvwidget = loaded_widgets; poshidwid = loaded_hidwids; if(prvwidget){ for(wpom = prvwidget; wpom->next; wpom = wpom->next); for(; wpom; wpom = wpom->prev){ wpom->hide = 0; if(wpom->obr){ if(wpom->obr->scaled != ratio){ rescalePixmap(wpom->obr->ibarvy, &wpom->obr->barvy); rescalePixmap(wpom->obr->ikanal, &wpom->obr->akanal); wpom->obr->scaled = ratio; } wpom->okno = XCreateSimpleWindow(display, win, wpom->x*ratio, wpom->y*ratio, wpom->obr->PIX_SIR*ratio, wpom->obr->PIX_VYS*ratio, 0, BlackPixel(display,screen), WhitePixel(display,screen)); XShapeCombineMask (display, wpom->okno, ShapeBounding, 0, 0, wpom->obr->akanal, ShapeSet); XSetWindowBackgroundPixmap(display, wpom->okno, wpom->obr->barvy); XMapWindow(display, wpom->okno); } } } for(wpom = poshidwid; wpom; wpom = wpom->next) wpom->hide = 1; mengraf = 1; // Submapy: autoreloadmap = 1; deleteAsubmaps(); prvsubmap = loaded_submaps; prvhidsm = loaded_hidmaps; bgmap = loaded_bgmap;
147
28 Moduly save a load 1121: 1122: 1123: 1124: 1125: 1126: 1127: 1128: 1129: 1130: 1131: 1132: 1133: 1134: 1135: 1136: 1137: 1138: 1139: 1140: 1141: 1142: 1143: 1144: 1145: 1146: 1147: 1148: 1149: 1150: 1151: 1152: 1153: 1154: 1155: 1156: 1157: 1158: 1159: 1160: 1161: 1162: 1163: 1164: 1165: }
Program kraluk
for(smpom = prvsubmap; smpom; smpom = smpom->next){ smpom->map = nactimapu(smpom->nazev); smpom->hide = 0; } for(smpom = prvhidsm; smpom; smpom = smpom->next){ smpom->map = nactimapu(smpom->nazev); smpom->hide = 1; } reloadmap(); // Animace postav: deleteAanips(); prvanip = loaded_anips; // Postavy: deleteAposts(); prvpost = loaded_posts; menpost = 1; // Timery: deleteAtimers(); prvtimer = loaded_timers; pausedtimers = loaded_pautims; //: Predmety: deleteApredmets(); prvpredmet = loaded_predmets; for(prpom = prvpredmet; prpom; prpom = prpom->next){ if(prpom->inv){ prpomo = &inventar; while(*prpomo && prpom->inv < (*prpomo)->inv) prpomo = &(*prpomo)->polnext; prpom->polnext = *prpomo; *prpomo = prpom; } else if(prpom->pol){ prpom->polnext = prpom->pol->predmety; prpom->pol->predmety = prpom; } if(prpom->slovo) prpom->slovo->informace.u.p = prpom; }
Pokud načítání selže, je dobré funkcí free_loaded uvolnít z paměti to, co jsem namallokoval. load.c 969: void free_loaded () 970: { 971: int i; 972: kq_pixmap *ppom, *ppomo; 973: kq_widget *wpom, *wpomo; 974: kq_submap *smpom, *smpomo; 975: kq_animpost *appom, *appomo; 976: kq_postava *popom, *popomo; 977: kq_timer *tpom, *tpomo; 978: kq_predmet *prpom, *prpomo; 979: 980: for(ppom = loaded_pixmaps; ppom; ppom = ppomo){ 981: ppomo = ppom->next; 982: if(ppom->nazev) free(ppom->nazev); 983: free(ppom); 984: } 985: for(wpom = loaded_widgets; wpom; wpom = wpomo){ 986: wpomo = wpom->next; void free_loaded(): 148, 160
148
28 Moduly save a load 987: 988: 989: 990: 991: 992: 993: 994: 995: 996: 997: 998: 999: 1000: 1001: 1002: 1003: 1004: 1005: 1006: 1007: 1008: 1009: 1010: 1011: 1012: 1013: 1014: 1015: 1016: 1017: 1018: 1019: 1020: 1021: 1022: 1023: 1024: 1025: 1026: 1027: 1028: 1029: 1030: 1031: 1032: 1033: 1034: }
Program kraluk
free(wpom); } for(wpom = loaded_hidwids; wpom; wpom = wpomo){ wpomo = wpom->prev; free(wpom); } for(smpom = loaded_submaps; smpom; smpom = smpomo){ smpomo = smpom->next; if(smpom->nazev) free(smpom->nazev); free(smpom); } for(smpom = loaded_hidmaps; smpom; smpom = smpomo){ smpomo = smpom->next; if(smpom->nazev) free(smpom->nazev); free(smpom); } for(appom = loaded_anips; appom; appom = appomo){ appomo = appom->next; if(appom->pix.pole && (appom->framu > 1 || (appom->framu == 1 && !appom->jednopol))) free(appom->pix.pole); free(appom); } for(popom = loaded_posts; popom; popom = popomo){ popomo = popom->next; free(popom); } for(tpom = loaded_timers; tpom; tpom = tpomo){ tpomo = tpom->next; free(tpom); } for(tpom = loaded_pautims; tpom; tpom = tpomo){ tpomo = tpom->next; free(tpom); } for(prpom = loaded_predmets; prpom; prpom = prpomo){ prpomo = prpom->next; if(prpom->nazev) free(prpom->nazev); free(prpom); } if(loaded_apole){ for(i=0; ipocetanim; i++){ if(loaded_apole[i].pix) free(loaded_apole[i].pix); if(loaded_apole[i].casy) free(loaded_apole[i].casy); } free(loaded_apole); }
Další funkce jsou už jen jednoduchými ekvivalenty funkcí z modulu save. Nejdříve ukážu ekvivalent k funkci save_kontexts, tedy funkci load_kontexts. Tato funkce neukládá načtené kontexty do položky kontext ve slově, ale do položky loaded_kontext. Do položky kontext se uloží až ve funkci apply_load. load.c 589: void load_kontexts () 590: { 591: kq_word *pom; 592: 593: for(pom = prvulslovo; pom; pom = pom->next) 594: pom->loaded_kontext = load_int(); 595: }
Ekvivalent k funkci save_word: load.c 599: kq_word *load_word () 600: { 601: kq_word *vysledek; void load_kontexts(): 149, 160
kq_word *load_word(): 153, 157
149
28 Moduly save a load 602: 603: 604: 605: 606: 607: 608: 609: 610: 611: }
Program kraluk
int i; i = load_intoddo(0, pocet_word); if(i == 0 || chyba) return NULL; for(vysledek = prvulslovo; vysledek && i>1; vysledek = vysledek->next) i--; return vysledek;
Ekvivalent k funkci save_pixmaps: load.c 615: void load_pixmaps () 616: { 617: kq_pixmap *pom; 618: 619: for(pom = loaded_pixmaps; !chyba && pom; pom = pom->next){ 620: pom->lokalni = load_bit(); 621: pom->nazev = load_string(); 622: } 623: }
Ekvivalent k funkci save_pixmap: load.c 627: kq_pixmap *load_pixmap() 628: { 629: int i; 630: kq_pixmap *vysledek; 631: 632: i = load_intoddo(pocet_fixpix, pocet_pix); 633: if(chyba || i == 0) return NULL; 634: 635: if(i > 0) for(vysledek = loaded_pixmaps; vysledek && i>1; vysledek = vysledek->next) i--; 636: else for(vysledek = fixed_pixmaps; vysledek && i<-1; vysledek = vysledek->next) i++; 637: 638: return vysledek; 639: }
Ekvivalent k funkci save_winfo: load.c 643: void load_winfo (kq_widget *w) 644: { 645: w->obr = load_pixmap(); 646: w->x = load_int(); 647: w->y = load_int(); 648: w->z = load_float(); 649: w->lokalni = load_trit(); 650: }
Ekvivalent k funkci save_widgets: load.c 654: void load_widgets () 655: { 656: kq_widget *pom; 657: 658: for(pom = loaded_widgets; !chyba && pom; pom = pom->next) load_winfo(pom); 659: for(pom = loaded_hidwids; !chyba && pom; pom = pom->prev) load_winfo(pom); 660: }
Ekvivalent k funkci save_widget: load.c 664: kq_widget *load_widget () 665: { 666: kq_widget *vysledek; 667: int i; void load_pixmaps(): 160 void load_widgets(): 160
kq_pixmap *load_pixmap(): 150, 152, 155, 157 kq_widget *load_widget(): 153, 155, 157
150
void load_winfo(): 150
28 Moduly save a load 668: 669: 670: 671: 672: 673: 674: 675: 676: 677: }
Program kraluk
i = load_intoddo(pocet_hwid, pocet_wid); if(i == 0 || chyba) return NULL; if(i > 0) for(vysledek = loaded_widgets; vysledek && i>1; vysledek = vysledek->next) i--; else for(vysledek = loaded_hidwids; vysledek && i<-1; vysledek = vysledek->prev) i++; return vysledek;
Ekvivalent k funkci save_sminfo: load.c 681: void load_sminfo (kq_submap *sm) 682: { 683: sm->nazev = load_string(); 684: sm->x = load_int(); 685: sm->y = load_int(); 686: sm->z = load_float(); 687: sm->lokalni = load_trit(); 688: }
Ekvivalent k funkci save_submaps: load.c 692: void load_submaps () 693: { 694: kq_submap *pom; 695: 696: loaded_bgmap = load_submap(); 697: for(pom = loaded_submaps; !chyba && pom; pom = pom->next) load_sminfo(pom); 698: for(pom = loaded_hidmaps; !chyba && pom; pom = pom->next) load_sminfo(pom); 699: }
Ekvivalent k funkci save_submap: load.c 703: kq_submap *load_submap () 704: { 705: kq_submap *vysledek; 706: int i; 707: 708: i = load_intoddo(pocet_hsm, pocet_sm); 709: 710: if(i == 0 || chyba) return NULL; 711: 712: if(i > 0) for(vysledek = loaded_submaps; vysledek && i>1; vysledek = vysledek->next) i--; 713: else for(vysledek = loaded_hidmaps; vysledek && i<-1; vysledek = vysledek->next) i++; 714: 715: return vysledek; 716: }
Ekvivalent k funkci save_anips: load.c 720: void load_anips () 721: { 722: kq_animpost *pom; 723: 724: int pocetpix, i; 725: 726: for(pom = loaded_anips; !chyba && pom; pom = pom->next){ 727: pom->x = load_int(); 728: pom->y = load_int(); 729: pom->framu = load_unsint(); 730: pom->tim = load_unsint(); 731: pom->jednopol = load_trit(); 732: pom->porad = load_bit(); 733: pom->lokalni = load_bit(); void load_sminfo(): 151 void load_anips(): 160
void load_submaps(): 160
151
kq_submap *load_submap(): 151–152, 157
28 Moduly save a load 734: 735: 736: 737: 738: 739: 740: 741: 742: 743: 744: 745: 746: 747: 748: 749: 750: 751: } 752: }
Program kraluk
pocetpix = pom->framu; if(!pom->jednopol) pocetpix *= 4; if(pocetpix < 1){ chyba = 1; warning("mene nez jedna (%d) pixmapa v animaci postavy", pocetpix); } else if(pocetpix == 1) pom->pix.map = load_pixmap(); else{ pom->pix.pole = (kq_pixmap **)malloc(pocetpix*sizeof(kq_pixmap *)); if(!pom->pix.pole){ chyba = 1; warning("load: malloc vratil NULL"); return; } for(i = 0; i < pocetpix; i++) pom->pix.pole[i] = load_pixmap(); }
Ekvivalent k funkci save_anip: load.c 756: kq_animpost *load_anip () 757: { 758: kq_animpost *vysledek; 759: int i; 760: 761: i = load_intoddo(pocet_fixanip, pocet_anip); 762: 763: if(i == 0 || chyba) return NULL; 764: 765: if(i > 0) for(vysledek = loaded_anips; vysledek && i>1; vysledek = vysledek->next) i--; 766: else for(vysledek = fixed_anips; vysledek && i<-1; vysledek = vysledek->next) i++; 767: 768: return vysledek; 769: }
Ekvivalent k funkci save_posts: load.c 773: void load_posts () 774: { 775: kq_postava *pom; 776: 777: for(pom = loaded_posts; !chyba && pom; pom = pom->next){ 778: pom->x = load_int(); 779: pom->y = load_int(); 780: pom->xx = load_int(); 781: pom->yy = load_int(); 782: pom->tim = load_timer(); 783: pom->zdi = load_bit(); 784: pom->barvy = load_bit(); 785: pom->odraz = load_bit(); 786: pom->odejde = load_bit(); 787: 788: pom->submap = load_submap(); 789: pom->sm_x = load_int(); 790: pom->sm_y = load_int(); 791: pom->chyt_vzdal = load_int(); 792: 793: pom->chyt_func = load_func(NULL); 794: pom->auto_func = load_func(NULL); 795: pom->free_func = load_func(NULL); 796: 797: if(load_bit() == 0){ 798: pom->autou_typ = AUTOU_SOUR; 799: pom->auto_u.sourad.x = load_int(); kq_animpost *load_anip(): 153, 157
void load_posts(): 160
152
28 Moduly save a load 800: 801: 802: 803: 804: 805: 806: 807: 808: 809: 810: 811: 812: 813: 814: 815: 816: 817: 818: 819: 820: } 821: }
Program kraluk
pom->auto_u.sourad.y = load_int(); } else{ pom->autou_typ = AUTOU_POST; pom->auto_u.sledpost = load_post(); } pom->auto_tim = load_timer(); pom->animace = load_anip(); pom->smer = load_unsint(); pom->animstav = load_unsint(); pom->animtim = load_timer(); pom->xz = load_float(); pom->yz = load_float(); pom->z = load_float(); pom->widget = load_widget(); pom->lokalni = load_trit(); pom->hide = load_bit(); pom->zmena = load_bit();
Ekvivalent k funkci save_post: load.c 825: kq_postava *load_post () 826: { 827: kq_postava *vysledek; 828: int i; 829: 830: i = load_intoddo(0, pocet_post); 831: 832: if(i == 0 || chyba) return NULL; 833: 834: for(vysledek = loaded_posts; vysledek && i>1; vysledek = vysledek->next) i--; 835: 836: return vysledek; 837: }
Ekvivalent k funkci save_predmets: load.c 841: void load_predmets () 842: { 843: kq_predmet *pom; 844: 845: for(pom = loaded_predmets; !chyba && pom; pom = pom->next){ 846: pom->slovo = load_word(); 847: pom->nazev = load_string(); 848: pom->inv = load_unsint(); 849: pom->stav = load_bit(); 850: pom->post = load_post(); 851: if(!pom->inv){ 852: pom->pol = load_pol(); 853: if(pom->pol){ 854: pom->pix_x = load_int(); 855: pom->pix_y = load_int(); 856: pom->pix_z = load_float(); 857: pom->sm_x = load_int(); 858: pom->sm_y = load_int(); 859: pom->sm_z = load_float(); 860: } 861: } 862: } 863: }
Ekvivalent k funkci save_predmet: kq_post *load_post(): 153, 157
void load_predmets(): 160
153
28 Moduly save a load
Program kraluk load.c
867: kq_predmet *load_predmet () 868: { 869: kq_predmet *vysledek; 870: int i; 871: 872: i = load_intoddo(0, pocet_predm); 873: 874: if(i == 0 || chyba) return NULL; 875: 876: for(vysledek = loaded_predmets; vysledek && i>1; vysledek = vysledek->next) i--; 877: 878: return vysledek; 879: }
Ekvivalent k funkci save_tinfo: load.c 907: void load_tinfo (kq_timer *tim) 908: { 909: tim->funkce = load_func(&tim->parametr); 910: if(!chyba && !tim->funkce){ 911: warning("funkce timeru je NULL"); 912: chyba = 1; 913: return; 914: } 915: tim->zbyva = load_unsint(); 916: tim->priorita = load_float(); 917: tim->opakovani = load_int(); 918: tim->cas = load_unsint(); 919: tim->pause = load_bit(); 920: tim->lokalni = load_trit(); 921: }
Ekvivalent k funkci save_timers: load.c 925: void load_timers () 926: { 927: kq_timer *pom; 928: 929: for(pom = loaded_timers; !chyba && pom; pom = pom->next) load_tinfo(pom); 930: for(pom = loaded_pautims; !chyba && pom; pom = pom->next) load_tinfo(pom); 931: }
Ekvivalent k funkci save_timer: load.c 935: kq_timer *load_timer () 936: { 937: kq_timer *vysledek; 938: int i; 939: 940: i = load_intoddo(pocet_ptim, pocet_tim); 941: 942: if(i == 0 || chyba) return NULL; 943: 944: if(i > 0) for(vysledek = loaded_timers; vysledek && i>1; vysledek = vysledek->next) i--; 945: else for(vysledek = loaded_pautims; vysledek && i<-1; vysledek = vysledek->next) i++; 946: 947: return vysledek; 948: }
Ekvivalent k funkci save_pol: load.c 952: kq_policko *load_pol () 953: { 954: int i; 955: kq_policko *vysledek;
kq_predmet *load_predmet(): 157 void load_tinfo(): 154 void load_timers(): 160 kq_timer *load_timer(): 152–153, 155, 157 kq_policko *load_pol(): 144, 153, 157
154
28 Moduly save a load 956: 957: 958: 959: 960: 961: 962: 963: 964: 965: }
Program kraluk
i = load_intoddo(0, pocet_pol); if(chyba || i == 0) return NULL; for(vysledek = prvpol; i>1 && vysledek; i--) vysledek = vysledek->next; return vysledek;
Ekvivalent k funkci save_awid: load.c 900: kq_anim *load_awid () 901: { 902: return &loaded_apole[load_intoddo(0, loaded_pol->pocetanim-1)]; 903: }
Ekvivalent k funkci save_awids: load.c 883: void load_awids () 884: { 885: int i, j; 886: 887: for(i=0; !chyba && ipocetanim; i++){ 888: loaded_apole[i].faze = load_intoddo(0, loaded_apole[i].pocet); 889: loaded_apole[i].widget = load_widget(); 890: loaded_apole[i].timer = load_timer(); 891: for(j=0; j
28.4
Registrované funkce a proměnné
Kromě všech vnitřních struktur je třeba ukládat ještě nějaká další data, která jsou uložena v jiných proměnných. Takovou proměnnou je třeba zaregistrovat funkcí add_sl_var. Tato funkce dostane dva parametry. Ukazatel na onu proměnnou a pak typ této proměnné, tedy jaký druh dat uchovává. K dispozici jsou následující možnosti: save.h 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
#define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define
SL_NULL SL_BOOL SL_TRIT SL_CHAR SL_INT SL_FLOAT SL_COLOR SL_PIXMAP SL_WIDGET SL_SUBMAP SL_ANIP SL_POST SL_TIMER SL_POL SL_PREDM SL_WORD SL_AWID
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// // // // // // // // // // // // // // // // //
nic pravdivostni hodnota - - - - - zaporne/nula/kladne - - - - - - znak - - - - - - - - - - - - - cele cislo - - - - - - - - - - - castecne realne cislo - - - - - ukazatel na aktualni barvu - - - ukazatel na pixmapu - - - - - - ukazatel na widget - - - - - - - ukazatel na submapu - - - - - - ukazatel na animaci postavy - - ukazatel na postavu - - - - - - ukazatel na timer - - - - - - - ukazatel na policko - - - - - - ukazatel na predmet - - - - - - ukazatel na slovo - - - - - - - ukazatel na animwid - - - - - - -
funkce funkce funkce funkce funkce funkce funkce funkce funkce funkce funkce funkce funkce funkce funkce funkce
save_bit save_trit save_char save_int save_float save_color save_pixmap save_widget save_submap save_anip save_post save_timer save_pol save_predmet save_word save_awid
kq_policko *load_awid: 157 kq_policko *load_awids: 160 SL_NULL: 244–245 SL_BOOL: 156–157, 244 SL_TRIT: 156–157, 245 SL_CHAR: 146, 156–157, 245 SL_INT: 146, 156–157, 245 SL_FLOAT: 147, 156–157 SL_COLOR: 156–159 SL_PIXMAP: 157 SL_WIDGET: 157, 245 SL_SUBMAP: 157, 244 SL_ANIP: 157, 245 SL_POST: 157, 159, 244–245 SL_TIMER: 157, 244 SL_POL: 157, 244 SL_PREDM: 157, 244 SL_WORD: 157 SL_AWID: 157, 159
155
28 Moduly save a load 25: #define SL_FUNC
17
// ukazatel na funkci
Program kraluk - - - - - - -
funkce save_func
Funkce add_sl_var pak tuto proměnnou zanese do seznamu struktury sl_var. Ta vypadá takto: save.h 40: struct sl_var{ 41: char typ; 42: void *ukazatel; 43: union{ 44: char ch; 45: int i; 46: float f; 47: void *p; 48: } loaded; 49: 50: sl_var *next; 51: };
Funkce add_sl_var tedy vypadá takto: save.c 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481:
sl_var *prvslvar = NULL; void add_sl_var (void *p, char typ) { sl_var *pom; pom = (sl_var *)mymalloc(sizeof(sl_var)); pom->next = prvslvar; prvslvar = pom; pom->ukazatel = p; pom->typ = typ; }
Pro uložení takto zaregistrovaných proměnných je k dispozici funkce save_vars save.c 448: void save_vars () 449: { 450: sl_var *pom; 451: 452: for(pom = prvslvar; !chyba && pom; pom = pom->next){ 453: if(pom->typ >= SL_COLOR && pom->typ <= SL_FUNC) 454: save_pointer(*(void **)pom->ukazatel, pom->typ); 455: else if(pom->typ == SL_BOOL) save_bit(*(char *)pom->ukazatel); 456: else if(pom->typ == SL_TRIT) save_trit(*(char *)pom->ukazatel); 457: else if(pom->typ == SL_CHAR) save_char(*(char *)pom->ukazatel); 458: else if(pom->typ == SL_INT) save_int(*(int *)pom->ukazatel); 459: else if(pom->typ == SL_FLOAT) save_float(*(float *)pom->ukazatel); 460: else{ 461: warning("promenna nema prideleny typ"); 462: chyba = 1; 463: } 464: } 465: }
Pro načtení takto uložených hodnot existuje funkce load_vars. Tato funkce uloží načtenou hodnotu do položky loaded ve struktuře sl_var. K uložení do skutečné proměnné, jejíž ukazatel je v položce ukazatel dojde až ve funkci apply_load. load.c 568: void load_vars () 569: { 570: sl_var *pom; 571: 572: for(pom = prvslvar; !chyba && pom; pom = pom->next){ 573: if(pom->typ >= SL_COLOR && pom->typ <= SL_FUNC) 574: pom->loaded.p = load_pointer(pom->typ); SL_FUNC: 156–159, 244 struct sl_var: 7, 146, 156 void add_sl_var(): 37, 155–156, 159, 244–245 void save_vars(): 156, 160 void load_vars(): 156, 160
156
28 Moduly save a load 575: 576: 577: 578: 579: 580: 581: 582: 583: 584: } 585: }
else if(pom->typ == else if(pom->typ == else if(pom->typ == else if(pom->typ == else if(pom->typ == else{ warning("promenna chyba = 1; }
Program kraluk SL_BOOL) pom->loaded.ch SL_TRIT) pom->loaded.ch SL_CHAR) pom->loaded.ch SL_INT) pom->loaded.i = SL_FLOAT) pom->loaded.f
= load_bit(); = load_trit(); = load_char(); load_int(); = load_float();
nema prideleny typ");
Pro ukládání a načítání typů, které jsou ukazatelem, používám speciální funkce save_pointer a load_pointer: save.c 366: void save_pointer (void *p, char typ) 367: { 368: switch(typ){ 369: case SL_COLOR: save_color(p); 370: case SL_PIXMAP: save_pixmap(p); 371: case SL_WIDGET: save_widget(p); 372: case SL_SUBMAP: save_submap(p); 373: case SL_ANIP: save_anip(p); 374: case SL_POST: save_post(p); 375: case SL_TIMER: save_timer(p); 376: case SL_POL: save_pol(p); 377: case SL_PREDM: save_predmet(p); 378: case SL_WORD: save_word(p); 379: case SL_AWID: save_awid(p); 380: case SL_FUNC: save_func(p, NULL); 381: default: 382: warning("neznamy typ pointeru"); 383: chyba = 1; 384: } 385: }
break; break; break; break; break; break; break; break; break; break; break; break;
load.c 505: void *load_pointer (char 506: { 507: switch(typ){ 508: case SL_COLOR: return 509: case SL_PIXMAP: return 510: case SL_WIDGET: return 511: case SL_SUBMAP: return 512: case SL_ANIP: return 513: case SL_POST: return 514: case SL_TIMER: return 515: case SL_POL: return 516: case SL_PREDM: return 517: case SL_WORD: return 518: case SL_AWID: return 519: case SL_FUNC: return 520: default: 521: warning("neznamy typ 522: chyba = 1; 523: } 524: return NULL; 525: }
typ)
load_color(); load_pixmap(); load_widget(); load_submap(); load_anip(); load_post(); load_timer(); load_pol(); load_predmet(); load_word(); load_awid(); load_func(NULL); pointeru");
Tyto speciální funkce mám kvůli registrovaným funkcím. Některé ukládané struktury obsahují ukazatel na funkci a je třeba nějak takovou funkci identifikovat. Při ukládání takových funkcí je vybíráno ze seznamu a je uloženo pořadí nalezené funkce. Do toho seznamu ukládá funkce add_sl_func. Tato funkce dostane ukazatel na funkci a typ. Typ určuje typ parametru, který má funkce dostat. void save_pointer(): 156–158 add_sl_func(): 158–159, 244–245
void *load_pointer(): 156–157, 159
157
void
28 Moduly save a load
Program kraluk save.c
429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444:
sl_func *prvslfunc = NULL; int pocet_func = 0; void add_sl_func (void (*f)(), char typ) { sl_func *pom; pom = (sl_func *)mymalloc(sizeof(sl_func)); pom->next = prvslfunc; prvslfunc = pom; pom->funkce = f; pom->typ = typ; pocet_func++; }
Seznam funkcí tvoří struktura sl_func: save.h 29: 30: 31: 32: 33: 34: 35: 36:
struct sl_func{ char typ; void (*funkce)(); sl_func *next; }; sl_func *prvslfunc; int pocet_func;
Položka typ je ve struktuře sl_func kvůli timerům. V nich je totiž využíván kq_pin pro parametr funkce, ale datový typ kq_pin neurčuje, o jaký typ pointeru se jedná. Funkce save_func pro uložení funkce do souboru může jako druhý parametr dostat ukazatel na kq_pin a pak je uložen i obsah tohoto kq_pin. V případě, že ukládaná funkce žádný parametr nemá, je možné místo ukazatele na kq_pin napsat NULL. save.c 389: void save_func (void (*f)(), kq_pin *parametr) 390: { 391: sl_func *pom; 392: int i; 393: 394: if(!f){ 395: save_intoddo(0, 0, pocet_func); 396: return; 397: } 398: 399: i=1; 400: for(pom = prvslfunc; pom && pom->funkce != f; pom = pom->next) i++; 401: 402: if(!pom){ 403: warning("funkce nenalezena"); 404: save_intoddo(0, 0, pocet_func); 405: return; 406: } 407: 408: save_intoddo(i, 0, pocet_func); 409: if(!parametr) return; 410: 411: if(parametr->typ == PINNULL) save_trit(0); 412: else if(parametr->typ == PININT){ 413: save_trit(-1); 414: save_int(parametr->u.i); 415: } 416: else{ 417: save_trit(1); 418: if(pom->typ >= SL_COLOR && pom->typ <= SL_FUNC) 419: save_pointer(parametr->u.p, pom->typ); struct sl_func: 7, 158–159
void save_func(): 140, 142, 156–159
158
28 Moduly save a load
Program kraluk
420: else{ 421: warning("funkce nema pridelen typ parametru (typ = %d)"); 422: chyba = 1; 423: } 424: } 425: }
Podobně funguje funkce load_func, která vrátí uloženou funkci. Parametr této funkce může být NULL nebo ukazatel na kq_pin. Pokud to NULL není, je do tohoto ukazatele uloženo to, co tam uložila funkce save_func. load.c 529: void (*load_func (kq_pin *parametr))() 530: { 531: sl_func *pom; 532: int i; 533: 534: i = load_intoddo(0, pocet_func); 535: 536: if(i == 0 || chyba) return NULL; 537: 538: for(pom = prvslfunc; pom && i > 1; pom = pom->next) i--; 539: 540: if(!pom){ 541: warning("funkce nenalezena"); 542: chyba = 1; 543: return NULL; 544: } 545: 546: if(parametr){ 547: i = load_trit(); 548: if(i == 0) parametr->typ = PINNULL; 549: else if(i < 0){ 550: parametr->typ = PININT; 551: parametr->u.i = load_int(); 552: } 553: else{ 554: parametr->typ = PINPOINTER; 555: if(pom->typ >= SL_COLOR && pom->typ <= SL_FUNC) 556: parametr->u.p = load_pointer(pom->typ); 557: else{ 558: warning("funkce nema pridelen typ parametru"); 559: chyba = 1; 560: } 561: } 562: } 563: return pom->funkce; 564: }
Některé funkce a proměnné je dobré mít zaregistrované od začátku. To zařídí funkce init_sl, která je spuštěna na začátku programu funkcí kql_init. save.c 45: void init_sl () 46: { 47: add_sl_func(&jdipost, SL_POST); 48: add_sl_func(&anip_step, SL_POST); 49: add_sl_func(&animuj, SL_AWID); 50: 51: add_sl_func(&auto_random, SL_POST); 52: add_sl_func(&auto_primo, SL_POST); 53: add_sl_func(&auto_clever, SL_POST); 54: 55: add_sl_var(&ovlpost, SL_POST); 56: }
void *load_func(): 152, 154, 157, 159
void init_sl(): 159, 187
159
28 Moduly save a load
28.5
Program kraluk
Všechno dohromady
Funkcí pro ukládání a načítání je vskutku hodně, a proto je vhodné je zabalit do další funkce, které se předá jen název souboru, a ona kompletně uloží nebo načte pozici. Všechny ukládací funkce jsou shrnuty ve funkci save_all. save.c 780: void save_all (char *filename) 781: { 782: printf("SAVE: %s/%s\n", homedir, filename); 783: 784: save_start(filename); 785: save_idstr(); 786: save_pocty(); 787: save_pixmaps(); 788: save_widgets(); 789: save_submaps(); 790: save_anips(); 791: save_posts(); 792: save_timers(); 793: save_kontexts(); 794: save_predmets(); 795: save_awids(); 796: save_vars(); 797: save_cs(); 798: 799: save_end(); 800: if(chyba) warning("CHYBA PRI UKLADANI"); 801: }
Všechny ukládací funkce jsou shrnuty ve funkci load_all. load.c 1169: void load_all (char *filename) 1170: { 1171: printf("LOAD: \%s/%s\n", homedir, filename); 1172: 1173: load_start(filename); 1174: if(!soubor){ 1175: warning("soubor %s nemohl byt otevren pro cteni", filename); 1176: return; 1177: } 1178: check_idstr(); 1179: load_pocty(); 1180: load_pixmaps(); 1181: load_widgets(); 1182: load_submaps(); 1183: load_anips(); 1184: load_posts(); 1185: load_timers(); 1186: load_kontexts(); 1187: load_predmets(); 1188: load_awids(); 1189: load_vars(); 1190: check_cs(); 1191: 1192: load_end(filename); 1193: if(chyba) free_loaded(); 1194: else apply_load(); 1195: if(chyba) warning("CHYBA PRI NACITANI"); 1196: }
Podobně jako předchozí funkce ukládají a načítají pozici, zde na stejném principu existují funkce, které ukládají nastavení a historii. Tyto údaje jsou načteny při startu programu a uloženy při jeho ukončení. Konkrétně je tedy uloženo: • rychlost programu (aktuFPS) void save_all(): 160, 165, 188
void load_all(): 160, 165, 188
160
28 Moduly save a load • • • •
Program kraluk
velikost programu (ratio) stav fullscreenu (fullscreened), případně velikost po odfullscreenování (unfullratio) mód text/win (okrajwin) historie příkazů včetně aktuálně napsaného save.c
805: void save_conf () 806: { 807: if(!SAVECONF) return; 808: 809: printf("SAVE_CONF: %s/%s\n", homedir, SAVECONF); 810: save_start(SAVECONF); 811: save_hist(); 812: save_bit(okrajtext); 813: save_unsint(ratio); 814: save_bit(fullscreened); 815: if(fullscreened) save_unsint(unfullratio); 816: save_intoddo(aktuFPS, 0, maxFPS); 817: save_string(aktulang->informace.u.p); 818: save_end(); 819: }
Jelikož historie je uložena ve statických proměnných modulu edit, mám tam funkci save_hist, která tyto statické proměnné uloží do souboru, a funkci apply_loaded_hist, která zkopíruje načtená data do oněch statických proměnných. Při načítání konfigurace si počínám podobně, jako při načítání pozice. Tedy ukládám si načtené hodnoty a teprve v případě úspěšného načtení jsou tato data uložena do ostrých proměnných. Proměnné, do kterých jsou data přechodně ukládána, jsou však v tomto případě nejen statická, ale i lokální a jsou ve tvaru l_promenna. load.c 1200: void load_conf () 1201: { 1202: int *l_delhist; 1203: char **l_hist; 1204: int l_poceth, l_aktuh, l_FPS, l_ratio, l_unfullratio; 1205: char l_okrajtext, l_fullscreened; 1206: char *l_lang; 1207: kq_word *jazyk; 1208: 1209: int i, j; 1210: 1211: if(!SAVECONF){ 1212: zmenFPS(0); 1213: return; 1214: } 1215: load_start(SAVECONF); 1216: 1217: if(!soubor){ 1218: zmenFPS(0); 1219: return; 1220: } 1221: printf("LOAD_CONF: %s/%s\n", homedir, SAVECONF); 1222: 1223: l_poceth = load_unsint(); 1224: l_aktuh = load_unsint(); 1225: if(chyba){ 1226: l_delhist = NULL; 1227: l_hist = NULL; 1228: } 1229: else{ 1230: l_delhist = (int *)malloc((l_poceth+1)*sizeof(int)); 1231: if(!l_delhist){ 1232: l_hist = NULL; 1233: warning("malloc vratil NULL");
void save_conf(): 188
void load_conf(): 187
161
29 Modul gsl 1234: 1235: 1236: 1237: 1238: 1239: 1240: 1241: 1242: 1243: 1244: 1245: 1246: 1247: 1248: 1249: 1250: 1251: 1252: 1253: 1254: 1255: 1256: 1257: 1258: 1259: 1260: 1261: 1262: 1263: 1264: 1265: 1266: 1267: 1268: 1269: 1270: 1271: 1272: 1273: 1274: 1275: 1276: 1277: 1278: 1279: 1280: 1281: 1282: 1283: 1284: 1285: 1286: 1287: 1288: 1289: 1290: 1291: 1292: 1293: 1294: }
Program kraluk
chyba = 1; } else{ l_hist = (char **)malloc((l_poceth+1)*sizeof(char *)); if(!l_hist){ warning("malloc vratil NULL"); chyba = 1; } } } for(i=l_poceth; i >= 0 && !chyba; i--) l_delhist[i] = load_unsint(); check_cs(); if(l_hist){ for(i=l_poceth; i >= 0; i--){ if(chyba) l_hist[i] = NULL; else{ l_hist[i] = (char *)malloc((l_delhist[i]+1)*sizeof(char)); if(!l_hist[i]){ warning("malloc vratil NULL"); chyba = 1; } } } for(i=l_poceth; i >= 0 && !chyba; i--){ for(j=0; jinformace.u.p); jazyk = jazyk->next); if(jazyk) aktulang = jazyk; else printf("neznamy jazyk ’%s’\n", l_lang); } if(l_hist) free(l_hist); if(l_lang) free(l_lang);
29 Modul gsl Název GSL je zkratka pro Grafický Save a Load. Tento modul kombinuje možnosti tří (čtyř) modulů, tedy edit, popup, save a load. 162
29 Modul gsl
Program kraluk
Základní funkcí tohoto modulu je popup_sl. Tato funkce dostane string nadpisu nad názvy souborů a funkci, kterou má na vybraný soubor zavolat. Tato funkce, podobně jako celá hra, může být ve dvou fázích. Buď je okraj na win, potom je šipkami vybírána pozice ze seznamu a příslušná pozice je vždy zobrazena v políčku textwin, nebo je okraj na textwin a v seznamu jsou jen ty pozice, které začínají na to, co je napsáno v textwin. Při zmáčknutí klapky se do lokální proměnné prepocitej uloží informace, zda je třeba změnit tu část, která právě není aktivní. Nakonec funkce aplikuje funkci z parametru na vybranou pozici. gsl.c 107: void popup_sl (char *nadpis, void (*funkce)(char *)) 108: { 109: char **seznam; // seznam vsech pozic 110: char **filznam; // seznam zobrazenych pozic 111: char *fullname; 112: char ch, prepocitej; 113: int pocet; // pocet vsech pozic 114: char *str; 115: char ministr[2]; // pole pro nahrazeni textpole jednim znakem (pomoci zmentext) 116: char sltextpole[STRINGSIZE]; // nahradni pole pro editaci textu 117: 118: char *otext; // stav pred spustenim teto funkce 119: int ogursor, odelka, ogelka, ocursor, oposunuti, ohist, ookr; 120: 121: seznam = prectidir(&pocet); 122: filznam = (char **)mymalloc((pocet+1) * sizeof(char *)); 123: filtruj(seznam, "", filznam); 124: 125: zalohujtext(&ocursor, &odelka, &ogursor, &ogelka, &oposunuti); 126: ohist = aktuhist; 127: otext = text_pole; 128: ookr = okrajtext; 129: aktuhist = -1; 130: text_pole = sltextpole; 131: 132: if(filznam[0]){ 133: if(okrajtext) okraj_to_win(); 134: zmentext(filznam[0]); 135: aktuselect = 0; 136: } 137: else{ 138: if(!okrajtext) okraj_to_text(); 139: zmentext(""); 140: aktuselect = -1; 141: } 142: vytvorpsel(DEF_POP_SIRKA, DEF_POP_VYSKA, DEF_POP_X, DEF_POP_Y, 143: nadpis, filznam, aktuselect, 0); 144: 145: ministr[1] = 0; 146: 147: XEvent report; 148: 149: for(;;){ 150: XNextEvent(display, &report); 151: if(report.type == KeyPress){ 152: prepocitej = 0; 153: if(report.xkey.keycode == KEY_ESC){ 154: if((okrajtext || filtrovano) && seznam[0]){ 155: if(okrajtext) okraj_to_win(); 156: aktuselect = 0; 157: popup_selpocet(filtruj(seznam, "", filznam)); 158: zmentext(filznam[0]); 159: clearselect(); 160: drawselect(); 161: } 162: else{ void popup_sl(): 24, 163, 165
163
29 Modul gsl 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230:
Program kraluk
str = NULL; break; } } else if(report.xkey.keycode == KEY_ENTER){ str = textcstr(); if(str[0]) break; if(str != text_pole) free(str); } else if(report.xkey.keycode == KEY_TAB){ if(okrajtext){ if(filznam[0]){ okraj_to_win(); aktuselect = 0; oznacsel(); smazkursor(); prepocitej = 1; } } else{ odoznacsel(); aktuselect = -1; okraj_to_text(); ukazkursor(); prepocitej = 1; } } else if(okrajtext){ if(report.xkey.keycode == KEY_LEFT) posunkursor(0); else if(report.xkey.keycode == KEY_RIGHT) posunkursor(1); else if(report.xkey.keycode == KEY_HOME) posunkursor(2); else if(report.xkey.keycode == KEY_END) posunkursor(3); else if(report.xkey.keycode == KEY_BACKSPACE) prepocitej = delete(1); else if(report.xkey.keycode == KEY_DELETE) prepocitej = delete(0); else{ ch = xkeyznak(&report); if(ch) prepocitej = pripisznak(ch); } } else{ prepocitej = aktuselect; if(report.xkey.keycode == KEY_UP) posunselect(-1); else if(report.xkey.keycode == KEY_DOWN) posunselect(1); else if(report.xkey.keycode == KEY_LEFT) posunselect(-2); else if(report.xkey.keycode == KEY_RIGHT) posunselect(2); else{ ch = xkeyznak(&report); if(ch){ okraj_to_text(); odoznacsel(); aktuselect = -1; ministr[0] = ch; zmentext(ministr); } } if(aktuselect == prepocitej) prepocitej = 0; else prepocitej = 1; } if(prepocitej){ if(!okrajtext) zmentext(filznam[aktuselect]); else{ str = textcstr(); if(prepocitej > 0) popup_selpocet(filtruj(seznam, str, filznam)); else popup_selpocet(filtruj(filznam, str, filznam)); // znak byl pripsan na konec if(str != text_pole) free(str); clearselect(); drawselect(); }
164
29 Modul gsl 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: }
Program kraluk
} } if(report.type == ButtonPress){ str = NULL; break; } if(report.type == Expose){ if(report.xexpose.window == textwin) redrawtext(); else drawpopup(1); } } zruspsel(); free(filznam); free(seznam); if(adresar) closedir(adresar); if(str){ fullname = joinstrings(str, SAVESUFFIX, NULL); funkce(fullname); free(fullname); } if(str != text_pole) free(str); odzaltext(ocursor, odelka, ogursor, ogelka, oposunuti); aktuhist = ohist; text_pole = otext; if(ookr != okrajtext){ if(ookr) okraj_to_text(); else okraj_to_win(); } cleartext(); redrawtext(); cekalose = 1;
Tuto funkci volají funkce gsave a gload: gsl.c 267: 268: 269: 270: 271: 272: 273: 274: 275:
void gsave() { popup_sl(outputstring("_save", NULL), save_all); } void gload() { popup_sl(outputstring("_load", NULL), load_all); }
Nejprve je třeba projít adresář homedir a soubory v něm seřadit podle času posledního zápisu, protože program vždy nabízí seznam pozic seřazený podle času uložení. Do proměnné adresar otevřu tento adresář, ale zavřu ho až po skončení výběru, protože zavřením se z paměti uvolní názvy pozic. Funkce prectidir tedy vrátí seznam pozic, který je rovnou možné předat funkci vytvorpsel. gsl.c 35: static DIR *adresar; 36: 37: char **prectidir (int *pocet) 38: { 39: struct dirent *de; 40: struct stat st; 41: int n, i, j, k, stare; 42: char *fullname; 43: struct fileinfo *files; 44: char **vysledek; 45: void gsave(): 20, 165 **prectidir(): 163, 165
void gload(): 20, 165
DIR adresar /*gsl*/ : 165–166
165
char
29 Modul gsl 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: }
Program kraluk
if(!homedir){ warning("nebyl zjisten domovsky adresar"); adresar = NULL; vysledek = (char **)mymalloc(sizeof(char *)); vysledek[0] = NULL; *pocet = 0; return vysledek; } if((adresar = opendir(homedir)) == NULL){ vysledek = (char **)mymalloc(sizeof(char *)); vysledek[0] = NULL; *pocet = 0; return vysledek; } for(n = 0; readdir(adresar); n++); rewinddir(adresar); if(n) files = mymalloc(sizeof(struct fileinfo)*n); for(i = 0; (de = readdir(adresar));){ j = strlen(de->d_name); k = strlen(SAVESUFFIX); while(j>0 && k>0 && de->d_name[--j] == SAVESUFFIX[--k]); if(k) continue; fullname = joinstrings(homedir, "/", de->d_name, NULL); stare = stat(fullname, &st); free(fullname); if(stare == -1) continue; de->d_name[j] = 0; files[i].nazev = de->d_name; files[i].mtime = st.st_mtime; i++; } n = i; qsort(files, n, sizeof(struct fileinfo), (int (*)(const void *, const void *))&porovnej); vysledek = (char **)mymalloc((n+1)*sizeof(char *)); for(i=0; i
Pro seřazení použiji pole struktury fileinfo, která obsahuje název bez přípony a čas vytvoření příslušného souboru. gsl.c 23: struct fileinfo{ 24: char *nazev; 25: time_t mtime; 26: };
Pole struktur fileinfo pak seřadím quicksortem pomocí porovnávací funkce porovnej. gsl.c 28: static int porovnej (struct fileinfo *a, struct fileinfo *b) 29: { 30: if(a->mtime > b->mtime) return -1; 31: if(a->mtime < b->mtime) return 1; 32: return 0; 33: }
Při psaní textu je však zobrazen seznam pouze těch pozic, které začínají na to, co je napsáno v řádku s textem. Proto funkci vytvorpsel nepředám rovnou seznam, ale filznam, což je proměnná, do
struct fileinfo: 165–166
int porovnej /*gsl*/ (): 166
166
30 Modul animwid
Program kraluk
které přefiltrovávám seznam všech pozic. Pro tento účel tu je funkce filtruj, které vrátí délku přefiltrovaného pole. Tato funkce dostane tři parametry. První je pole, z kterého jsou čerpány prvky, pak je string, podle kterého se prvky filtrují, a nakonec je pole, do kterého jsou prvky filtrovány. V případě, že je znak připsán na konec, je filtrováno už přefiltrované pole, tedy zdroj == cil. Do proměnné filtrovano uložím true v případě, že nejsou zobrazeny všechny pozice. gsl.c 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105:
static char filtrovano; static int filtruj (char **zdroj, char *str, char **cil) { int i, j, k; if(zdroj != cil) filtrovano = 0; for(i=j=0; zdroj[i]; i++){ for(k = 0; zdroj[i][k] && str[k] == zdroj[i][k]; k++); if(!str[k]) cil[j++] = zdroj[i]; else filtrovano = 1; } cil[j] = NULL; return j; }
30 Modul animwid V tomto modulu je založena struktura kq_anim. animwid.h 1: struct kq_anim{ 2: kq_pixmap **pix; 3: unsigned int *casy; 4: unsigned int pocet; 5: int faze; 6: kq_widget *widget; 7: kq_timer *timer; 8: };
Tato struktura narozdíl od ostatních nemá položku next a není tudíž členěna do seznamu. Kvůli tomu není možné animace ukládat, takže jediné možné využití je v modulu pol. V položce pix je pocet-členné pole pixmap a v položce casy je pocet-členné pole časů, po který bude příslušná pixmapa zobrazena. Funkce startanimwid předpokládá, že je již struktura na této úrovni připravena, a založí podle ní widget a timer. Widget umístí na dané souřadnice, timeru přiřadí parametry priorita a opakovani a jak timeru tak widgetu předá parametry lokalni a pauhide. animwid.c 24: void startanimwid (kq_anim *anim, int x, int y, float z, float priorita, 25: int opakovani, char lokalni, char pauhide) 26: { 27: anim->faze = 0; 28: anim->widget = vytvorwidget (x, y, z, anim->pix[0], lokalni, pauhide); 29: if(pauhide < 0) pauhide = 0; 30: anim->timer = vytvortimer(&animuj, pinpointer(anim), anim->casy[0], priorita, 31: opakovani, lokalni, pauhide); 32: }
Timer pak na strukturu opakovaně volá funkci animuj. Tato funkce posune položku faze o jedničku a nastaví příslušnou pixmapu widgetu a příslušný čas timeru. V případě, že by posunul položku faze mimo pole, pokračuje opět od nuly. animwid.c 9: void animuj (kq_anim *anim) 10: { 11: anim->faze++; 12: if(anim->faze >= anim->pocet) anim->faze = 0; 13: prebarviwidget(anim->widget, anim->pix[anim->faze]);
int filtruj /*gsl*/ (): 163–164, 167 char filtrovano /*gsl*/ : 163, 167 kq_anim: 7, 137, 143–144, 155, 167, 179 void startanimwid(): 167, 180 void animuj(): 137, 159, 167
167
31 Modul pol 14: 15: 16: 17: 18: 19: 20: 21: 22: }
Program kraluk
if(!aktutimer){ warning("animuj: chybi aktutimer"); return; } aktutimer->zbyva = anim->casy[anim->faze]; if(aktutimer->opakovani == 0) anim->timer = NULL;
31 Modul pol Tento modul řeší přepínání mezi políčky (scénami). Aby však bylo možné mezi políčky přepínat, je třeba nějaké políčko založit. Políčko je ukazatel na strukturu kq_policko, která vypadá takto: pol.h 53: struct kq_policko{ 54: kq_color *locbarva; 55: char *jmpixmap, *jmmapa; 56: int xa,xb,ya,yb; 57: kq_policko *vedle[4]; 58: void (*odchfunc)(kq_policko *odch, int smer, 59: kq_policko **prich, int *x, int *y); 60: void (*prichfunc)(kq_policko *odch, int smer, 61: kq_policko *prich); 62: int pocetanim; 63: struct pol_widget *pw; 64: struct pol_submap *psm; 65: struct pol_postava *pp; 66: kq_list *ps; 67: kq_predmet *predmety; 68: 69: kq_policko *next; 70: unsigned int Cislo; 71: };
První položka políčka locbarva souvisí s barvami. Funkce pridejbarvu obvykle přidá barvu do zásobníku začínajícího barvou prvbarva. Při hledání barvy pak je opět použit zásobník začínající barvou prvbarva. Tento modul však do barev vnáší jisté triky. Jakmile je založeno první políčko, jsou nové barvy přidávány pouze k naposledy založenému políčku a je možné tyto barvy použít jen v případě, že toto políčko je právě aktuální. Barvy, které byly založeny před prvním políčkem, je možné používat ve všech políčkách (jsou globální). První globální barva (ta, která byla založena naposledy) je globbarva a ukazují na ní poslední lokální barvy všech políček. pol.h 51: kq_color *globbarva;
Lokální barvy je možné používat jen v takových mapách, které se opravdu vyskytují jen na jednom políčku. Pokud založíte globální submapu, která obsahuje lokální barvu a pak přepnete na jiné políčko, bude fungovat skoro vše bez problémů, ale nebude pak možné uložit takovou pozici (případně ji pak načíst). Položka jmpixmap je string určující soubor, ze kterého je přečteno pozadí, a položka jmmapa určuje soubor, ze kterého je přečtena bgmap. Položky xa, xb, ya a yb jsou při zaktivnění políčka přesunuty do proměnných map_xa, map_xb, map_ya, map_yb. Každé políčko může sousedit se čtyřmi jinými políčky, tedy s jedním nahoře, s jedním dole, s jedním vlevo a s jedním v pravo. Tato sousední políčka jsou v položce vedle. Například políčko vpravo je v položce vedle[VPRAVO]. Při vytvoření políčka jsou všechna sousední políčka nastavena na NULL. Pro propojení dvourozměrného pole políček, mám předpřipravenou funkci spojpol. Tato funkce bude fungovat ovšem jen v případě, že bylo pole deklarováno jako dvourozměrné s jasně danými rozměry, tedy tváří se jako kq_policko: 7, 136, 138, 143, 154, 168–174, 176, 178, 181, 183, 191, 200, 203–205, 225, 227, 229, 231, 235, 237 kq_color *globbarva: 168–171 void spojpol(): 169, 196
168
31 Modul pol
Program kraluk
jednorozměrné. Funkce spojpol nejprve dostane pole, potom jeho rozměry a nakonec údaje, zda má pole torusoidně propojit horizontálně a vertikálně. pol.c 552: void spojpol (kq_policko **pole, int sirka, int vyska, 553: int htorus, int vtorus) 554: { 555: int i,j; 556: 557: for(i=0; ivedle[NAHORU] = pole[vyska-1 + j]; 562: } 563: else pole[i + j]->vedle[NAHORU] = pole[i-1 + j]; 564: if(i==vyska-1){ 565: if(vtorus) pole[i + j]->vedle[DOLU] = pole[j]; 566: } 567: else pole[i + j]->vedle[DOLU] = pole[i+1 + j]; 568: if(j==0){ 569: if(htorus) pole[i + j]->vedle[VLEVO] = pole[i + vyska*(sirka-1)]; 570: } 571: else pole[i + j]->vedle[VLEVO] = pole[i + j-vyska]; 572: if(j==vyska*(sirka-1)){ 573: if(htorus) pole[i + j]->vedle[VPRAVO] = pole[i]; 574: } 575: else pole[i + j]->vedle[VPRAVO] = pole[i + j+vyska]; 576: } 577: } 578: }
Další dvě položky jsou funkce odchfunc a prichfunc. Tyto funkce se spustí při přechodu postavy na jiné políčko, ale ne při ruční změně políčka. Funkce odchfunc se spustí jako první a dostane parametry: políčko, z kterého bylo odejito, směr, kterým bylo odejito, ukazatel na proměnnou s políčkem, na které bude přijito, ukazatel na X-ovou souřadnici, ukazatel na Y-ovou souřadnici. Tato funkce tedy může změnit jak políčko, tak souřadnice, na kterých se postava objeví. V případě, že smer je NAHORU, je však Y-ová souřadnice rovna -1 a počítá se od dolního okraje políčka. Stejně tak se počítá od levého okraje políčka X-ová souřadnice v případě, že smer == VLEVO. Funkce prichfunc dostane jednoduše políčko, z kterého bylo odejito, pak směr a nakonec políčko, do kterého bylo přijito. Tato funkce je spuštěna až v okamžiku, kdy je aktivní nové políčko a je na něm vše, co na něm má být. Stejně jako tyto funkce ještě existují funkce pol_odchfunc a pol_prichfunc, které však nejsou položkou uvnitř políčka, ale globální proměnnou, takže jsou společné pro všechna políčka. Tyto funkce jsou spuštěny okamžitě po ukončení přislušné funkce odchfunc či prichfunc. pol.c 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45:
void (*pol_prichfunc)(kq_policko *odch, int smer, kq_policko *prich) = NULL; #define PW_PIX 1 #define PW_WID 2 #define PW_ANIM 3 static pol_widget *pospw; static float rozdilz = 0; kq_policko *newpol (char *jmpixmap, char *jmmapa, int xa, int xb, int ya, int yb) { int i; if(aktupol){ aktupol->locbarva = prvbarva; prvbarva = globbarva; aktupol->next = (kq_policko *)mymalloc(sizeof(kq_policko)); void *pol_odchfunc(): 173, 191, 200
void *pol_prichfunc(): 169, 173, 209, 230, 233, 243–244
169
31 Modul pol 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64:
Program kraluk
aktupol = aktupol->next; } else{ globbarva = prvbarva; prvpol = aktupol = (kq_policko *)mymalloc(sizeof(kq_policko)); } aktupol->Cislo = ++pocet_pol; aktupol->jmpixmap = jmpixmap; aktupol->jmmapa = jmmapa; aktupol->xa = xa; aktupol->xb = xb; aktupol->ya = ya; aktupol->yb = yb; aktupol->pw = NULL; aktupol->psm = NULL; aktupol->pp = NULL; aktupol->ps = NULL; aktupol->predmety = NULL; aktupol->odchfunc = NULL;
Položky pocetanim a pw přidávají do políčka další widgety, položka psm přidává do políčka submapy a položka pp přidává do políčka postavy. Podrobněji budou tyto položky popsány, až budu vysvětlovat pol_widget, pol_submap a pol_postava. Další položka struktury kq_policko je list ps. To je seznam ukazatelů na slova, která se na políčku vyskytují. Při aktivaci políčka je všem slovům navýšena položka kontext o jedničku a při deaktivaci políčka je těmto slovům opět kontext o jedničku snížen. Funkce pridej_ps přidá slovo k naposledy založenému políčku. Ukazatele jsou použity proto, že v okamžiku použití této funkce jěště slova nejsou založena. pol.c 229: void pridej_ps (kq_word **w) 230: { 231: kq_list *pom; 232: 233: pom = (kq_list *)mymalloc(sizeof(kq_list)); 234: pom->u.p = w; 235: pom->next = aktupol->ps; 236: aktupol->ps = pom; 237: }
Všechny výše zmíněné položky struktury kq_policko se políčku přidělují na začátku programu a dále s nimi není možné hýbat, protože nejsou ukládány. Jediné, co je ukládáno a souvisí s políčky jsou předměty, tedy položka predmety. O těch je však celý modul predmet. Políčka jsou řazena do fronty začínající proměnnou prvpol a jejich počet je uložen v proměnné pocet_pol. Políčka jsou ve frontě propojena pomocí položky next. Proměnná aktupol ukazuje při tvoření políček na poslední prvek fronty políček, tedy na políčko, ke kterému jsou přidávány další údaje. Při hře je aktupol políčkem, které je právě zobrazené. pol.c 23: kq_policko *aktupol=NULL; 24: kq_policko *prvpol=NULL; 25: int pocet_pol = 0;
Funkce newpol založí nové políčko. Po spuštění této funkce je možné spouštet další funkce, které k políčku přidávají pixmapy, submapy, barvy, widgety, . . . pol.c 37: kq_policko *newpol (char *jmpixmap, char *jmmapa, 38: int xa, int xb, int ya, int yb) 39: { 40: int i; 41: 42: if(aktupol){ 43: aktupol->locbarva = prvbarva; 44: prvbarva = globbarva; void pridej_ps(): 170, 192–196, 200 kq_policko * prvpol: 155, 170–171 int pocet_pol: 136, 138, 155, 170–171 kq_policko *aktupol: 137, 139, 143, 169–173, 175–179, 181–182, 184, 188, 206, 209–216, 223–227, 230, 233, 238 void newpol(): 169–170, 191–197, 199–200
170
31 Modul pol 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: }
Program kraluk
aktupol->next = (kq_policko *)mymalloc(sizeof(kq_policko)); aktupol = aktupol->next; } else{ globbarva = prvbarva; prvpol = aktupol = (kq_policko *)mymalloc(sizeof(kq_policko)); } aktupol->Cislo = ++pocet_pol; aktupol->jmpixmap = jmpixmap; aktupol->jmmapa = jmmapa; aktupol->xa = xa; aktupol->xb = xb; aktupol->ya = ya; aktupol->yb = yb; aktupol->pw = NULL; aktupol->psm = NULL; aktupol->pp = NULL; aktupol->ps = NULL; aktupol->predmety = NULL; aktupol->odchfunc = NULL; aktupol->prichfunc = NULL; pospw = NULL; rozdilz = 0; aktupol->pocetanim = 0; for(i=0; i<4; i++) aktupol->vedle[i] = NULL; return aktupol;
Funkce set_pol nastaví políčko z parametru jako aktupol a zkopíruje z tohoto políčka některé údaje. Tuto funkci je vhodné spustit na začátku restartující funkce pro nastavení startovního políčka. pol.c 381: void set_pol (kq_policko *pol) 382: { 383: aktupol = pol; 384: prvbarva = aktupol->locbarva; 385: map_xa = aktupol->xa; 386: map_xb = aktupol->xb; 387: map_ya = aktupol->ya; 388: map_yb = aktupol->yb; 389: }
Funkce vykreslipol aplikuje aktuální políčko, tedy zobrazí a načte vše potřebné. pol.c 361: void vykreslipol () 362: { 363: kq_list *ps; 364: 365: for(ps=aktupol->ps; ps; ps = ps->next) 366: if(ps->u.p) (*((kq_word **)(ps->u.p)))->kontext++; 367: pol_postavy(); 368: 369: zmenokno(aktupol->jmpixmap); 370: pol_widgety(); 371: ukazwidgety(); 372: zobrazpredmety(); 373: 374: zmenbgmap(aktupol->jmmapa); 375: pol_submapy(); 376: reloadmap(); 377: 378: autoreloadmap = 1; 379: }
void set_pol(): 147, 171, 173, 187, 190
void vykreslipol(): 171, 173, 188
171
31 Modul pol
Program kraluk
Funkce prvnipol je spuštěna na začátku programu. Tato funkce předpokládá, že je již aktuální políčko nastaveno a jenom ho vykreslí, přičemž i zobrazí okno programu. pol.c 533: void prvnipol () 534: { 535: kq_list *ps; 536: 537: zmenbgmap(aktupol->jmmapa); 538: reloadmap(); 539: autoreloadmap = 1; 540: 541: for(ps=aktupol->ps; ps; ps = ps->next) 542: if(ps->u.p) (*((kq_word **)(ps->u.p)))->kontext++; 543: pol_postavy(); 544: pol_widgety(); 545: pol_submapy(); 546: zobrazpredmety(); 547: 548: vytvorokno(aktupol->jmpixmap); 549: ukazwidgety(); 550: }
Funkce polvedle je funkce, která je zavolána v okamžiku, kdy postava přechází z jedné obrazovky do jiné. Dostane postavu a směr, kterým z políčka utekla, a vrátí údaj, zda se změna políčka podařila. Neúspěchem může tato funkce skončit akorát v případě, že aktuální políčko nemá požadovaného souseda. Jinak si připraví příslušné souřadnice a přepne na příslušné políčko. Také spustí funkce odchfunc a prichfunc. pol.c 391: char polvedle (kq_postava *post, int smer) 392: { 393: int x,y,mx,my,vyhnout; 394: kq_policko *npol, *opol; 395: 396: if(!aktupol->vedle[smer]) return 0; 397: 398: x = post->x; 399: y = post->y; 400: mx = 0; 401: my = 0; 402: switch(smer){ 403: case NAHORU: 404: x+=post->xx; 405: my = 1; 406: y = -1; 407: vyhnout=1; 408: break; 409: case DOLU: 410: x+=post->xx; 411: y=0; 412: vyhnout=1; 413: break; 414: case VLEVO: 415: mx = 1; 416: x = -1; 417: y+=post->yy; 418: vyhnout=2; 419: break; 420: case VPRAVO: 421: x=0; 422: y+=post->yy; 423: vyhnout=2; 424: break; 425: } 426: npol = aktupol->vedle[smer]; 427: if(aktupol->odchfunc) aktupol->odchfunc(aktupol, smer, &npol, &x, &y); void prvnipol(): 172, 188
char polvedle(): 70, 172
172
31 Modul pol 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: }
Program kraluk
if(pol_odchfunc) pol_odchfunc(aktupol, smer, &npol, &x, &y); opol = aktupol; if(!post->zdi) vyhnout = 0; kql_square(post, npol, x, y, mx, my, vyhnout); if(npol->prichfunc) aktupol->prichfunc(opol, smer, npol); if(pol_prichfunc) pol_prichfunc(opol, smer, npol); return 1;
Funkcí pro změnu políčka je funkce kql_square. První parametr, který tato funkce dostane, je postava. V případě, že tato postava není NULL ani lokální, chová se tato funkce podobně jako posunpost (tedy zavolá se funkce při změně barev), ale posouvá mezi políčky. Druhý parametr je políčko, na které bude přepnuto. Parametry px a py jsou standardní cílové souřadnice postavy. Parametry mx a my se po vynásobení šířkou či výškou nové mapy přičtou k souřadnicím px a py. Tyto parametry zde mám proto, že nevím, jaké rozměry bude mít mapa na novém políčku. Pokud bych například chtěl mít postavu na předposledním řádku, předám do parametru px = -2 a do parametru mx = 1. Poslední parametr funkce kql_square je vyhnout. Ten určuje, co má program dělat, pokud je na požadovaných souřadnicích zeď. Když vyhnout == 0, tak se nic neděje a postava se tak objeví na zdi. Pokud vyhnout == 1, tak funkce hledá ve stejném řádku jako je postava nejbližší místo, kde zeď není, a když vyhnout == 2, tak funkce hledá nejbližší místo, kde zeď není ve sloupci. pol.c 440: void kql_square (kq_postava *post, kq_policko *pol, 441: int px, int py, int mx, int my, int vyhnout) 442: { 443: kq_color *b1; 444: pol_submap *psm; 445: pol_postava *pp; 446: kq_list *ps; 447: int x, y, x1, x2, ohide; 448: 449: if(post && post->lokalni > 0) post = NULL; 450: 451: if(post && mapa_z) b1 = mappixel(mapa, post->x,post->y); 452: else b1 = NULL; 453: 454: autoreloadmap = 0; 455: 456: if(post && post->submap){ 457: ohide = post->submap->hide; 458: hidesubmap(post->submap); 459: } 460: zmizpredmety(); 461: deletelanips(); 462: deletelposts(); 463: deletelsubmaps(); 464: deleteltimers(); 465: deletelwidgets(); 466: deletelpixmaps(); 467: free_animpole(); 468: for(psm=aktupol->psm; psm; psm = psm->next) 469: if(psm->ulozit) *psm->ulozit = NULL; 470: for(pp=aktupol->pp; pp; pp = pp->next) 471: if(pp->ulozit) *pp->ulozit = NULL; 472: for(ps=aktupol->ps; ps; ps = ps->next) 473: if(ps->u.p) (*((kq_word **)(ps->u.p)))->kontext--; 474: 475: set_pol(pol); 476: 477: vykreslipol(); 478: 479: if(!post) return; void kql_square(): 173, 209, 216–217, 221, 224–225, 233, 238
173
31 Modul pol 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: }
Program kraluk
zmenapost(post); if(!mapa_z){ post->x = px; post->y = py; return; } x = mapa.sirka*mx + px; y = mapa.vyska*my + py; if(x<0) x=0; if(y<0) y=0; if(x>=mapa.sirka) x=mapa.sirka-1; if(y>=mapa.vyska) y=mapa.vyska-1; if(mappixel(mapa, x,y)->zed){ if(vyhnout == 1) for(x1=x2=x; x1<mapa.sirka || x2>=0; x1++, x2--){ if(x1<mapa.sirka && ! mappixel(mapa, x1,y)->zed){ x=x1; break; } if(x2 >= 0 && ! mappixel(mapa, x2,y)->zed){ x=x2; break; } } if(vyhnout == 2) for(x1=x2=y; x1<mapa.vyska || x2>=0; x1++, x2--){ if(x1<mapa.vyska && ! mappixel(mapa, x,x1)->zed){ y=x1; break; } if(x2 >= 0 && ! mappixel(mapa, x,x2)->zed){ y=x2; break; } } } post->x = x; post->y = y; if(post->submap){ post->submap->x = x-post->sm_x; post->submap->y = x-post->sm_y; if(ohide) unhidesubmap(post->submap); } if(post->barvy && b1) spustfb(post, mappixel(mapa, x,y), b1);
Políčko dále může obsahovat submapy a postavy. Ve struktuře kq_policko je totiž seznam informací o tom, že se má tam a tam umístit submapa z určitého souboru. Tento seznam informací je skryt ve struktuře pol_submap, která je v kq_policko pod položkou psm. Struktura pol˙submap tedy vypadá takto: pol.h 24: struct pol_submap{ 25: int x, y; 26: float z; 27: char *filename; 28: char hide; 29: struct kq_submap **ulozit; 30: struct pol_submap *next; pol_submap: 8, 168, 170, 173–175
174
31 Modul pol
Program kraluk
31: };
Položky x, y a z jsou souřadnice submapy, filename je název souboru, z kterého je submapa čtena, a hide je údaj, zda má být submapa při vytvoření schovaná. Není možné submapě políčka nastavit lokálnost, protože je implicitně každá položka políčka lokální. Položka ulozit může obsahovat ukazatel, kam se daná submapa má nahrát. Při odchodu z políčka je pak do těchto ukazatelů vložen NULL. Funkce pridej_psm přidá k políčku submapu. pol.c 170: void pridej_psm (int x, int y, float z, char *nazev, char hide, kq_submap **ulozit) 171: { 172: pol_submap *pom; 173: 174: pom = (pol_submap *)mymalloc(sizeof(pol_submap)); 175: pom->x = x; 176: pom->y = y; 177: pom->z = z; 178: pom->filename = dupstr(nazev); 179: pom->hide = hide; 180: pom->ulozit = ulozit; 181: pom->next = aktupol->psm; 182: aktupol->psm = pom; 183: }
Funkce pol_submapy pak projde všechny submapy aktuálního políčka a vytvoří tak submapy skutečného políčka. pol.c 331: static void pol_submapy () 332: { 333: pol_submap *pom; 334: kq_submap *sm; 335: 336: for(pom = aktupol->psm; pom; pom = pom->next){ 337: sm = vytvorsubmap(pom->x, pom->y, pom->z, pom->filename, 1, pom->hide); 338: if(pom->ulozit) *pom->ulozit = sm; 339: } 340: }
Podobně jako jsou submapy políčka, existují i postavy políčka. To jsou struktury pol_postava, začleněny v seznamu pod položkou pp. pol.h 33: struct pol_postava{ 34: int x, y; 35: float xz, yz, z; 36: 37: char smer; 38: 39: char *sm_nazev; 40: int sm_x, sm_y; 41: float sm_z; 42: 43: char *a_nazev; 44: int a_framu, a_x, a_y, a_tim, a_jednopol, a_porad; 45: 46: char hide; 47: struct kq_postava **ulozit; 48: struct pol_postava *next; 49: };
Proměnné x, y, xz, yz, z, smer a hide se jednoduše zkopírují do skutečné postavy. Položky sm_nazev, sm_x, sm_y asm_z v případě, že sm_nazev není NULL, jsou použity pro funkci post_submap. Položky a_x, a_y, a_nazev, a_framu, a_tim, a_jednopol a a_porad jsou předány funkci nactianip, která vytvoří animaci určenou pro postavu. To se samozřejmě stane jen v případě, že v položce a_nazev není NULL. Funkce pridej_pp přidá k políčku postavu. Položka ulozit funguje stejně jako v případě pol_submap. void pridej_psm(): 175, 194 void pol_submapy /*pol*/ (): 171–172, 175 170, 173, 175–176 void pridej_pp(): 176, 194
175
pol_postava: 8, 168,
31 Modul pol
Program kraluk pol.c
185: void pridej_pp (int x, int y, char smer, char hide, kq_postava **ulozit, 186: float xz, float yz, float z, 187: char *sm_nazev, int sm_x, int sm_y, float sm_z, 188: char *a_nazev, int a_framu, char a_x, char a_y, 189: char a_tim, char a_jednopol, char a_porad) 190: { 191: pol_postava *pom; 192: 193: pom = (pol_postava *)mymalloc(sizeof(pol_postava)); 194: 195: pom->x = x; 196: pom->y = y; 197: pom->smer = smer; 198: pom->ulozit = ulozit; 199: 200: pom->xz = xz; 201: pom->yz = yz; 202: pom->z = z; 203: 204: if(sm_nazev){ 205: pom->sm_nazev = dupstr(sm_nazev); 206: pom->sm_x = sm_x; 207: pom->sm_y = sm_y; 208: pom->sm_z = sm_z; 209: } 210: else pom->sm_nazev = NULL; 211: 212: pom->hide = hide; 213: 214: if(a_nazev){ 215: pom->a_nazev = dupstr(a_nazev); 216: pom->a_framu = a_framu; 217: pom->a_x = a_x; 218: pom->a_y = a_y; 219: pom->a_tim = a_tim; 220: pom->a_jednopol = a_jednopol; 221: pom->a_porad = a_porad; 222: } 223: else pom->a_nazev = NULL; 224: 225: pom->next = aktupol->pp; 226: aktupol->pp = pom; 227: }
Funkce pol_postavy projde postavy aktuálního políčka a vytvoří podle nich skutečné postavy. pol.c 342: static void pol_postavy () 343: { 344: pol_postava *pom; 345: kq_postava *post; 346: 347: for(pom = aktupol->pp; pom; pom = pom->next){ 348: post = vytvorpost(pom->x, pom->y, pom->smer, 0, 0, 1, pom->hide); 349: post_z(post, pom->xz, pom->yz, pom->z); 350: 351: if(pom->a_nazev) 352: zmenanip(post, nactianip(pom->a_x, pom->a_y, pom->a_nazev, pom->a_framu, 353: pom->a_tim, pom->a_jednopol, pom->a_porad, 1)); 354: 355: if(pom->sm_nazev) post_submap(post, pom->sm_nazev, pom->sm_x, pom->sm_y, pom->sm_z); 356: 357: if(pom->ulozit) *pom->ulozit = post; 358: } 359: }
Další struktura, kterou k políčku ukládám, je pol_widget v položce pw struktury kq_policko. void pol_postavy /*pol*/ (): 171–172, 176
pol_widget: 8, 168–170, 177–180
176
31 Modul pol
Program kraluk
Tato struktura ovšem není tak jednoduchá jako předchozí dvě. Nepřiděluje totiž políčku jen widgety, ale i pixmapy a animované widgety. pol.h 1: struct pol_widget{ 2: char typ; 3: union{ 4: struct{ 5: int x,y; 6: float z; 7: } widget; 8: char *pixmap; 9: struct{ 10: float priorita; 11: int opakovani; 12: int pocet; 13: } anim; 14: struct{ 15: int pix1; 16: int cas1; 17: int pix2; 18: int cas2; 19: } pokranim; 20: } u; 21: struct pol_widget *next; 22: };
Seznam těchto struktur funguje jako fronta a ne jen jako seznam, takže je třeba, aby při ukládání do políčka byla známá poslední položka. Tu ukládám do proměnné pospw. pol.c 34: static pol_widget *pospw;
Funkce pw_alloc přidá do této fronty nový prvek. pol.c 76: static void pw_alloc () 77: { 78: pol_widget *pom; 79: 80: pom = (pol_widget *)mymalloc(sizeof(pol_widget)); 81: pom->next = NULL; 82: if(pospw) pospw->next = pom; 83: pospw = pom; 84: if(!aktupol->pw) aktupol->pw = pom; 85: }
Položka typ určuje, co se stane. Může nabývat tří hodnot: pol.c 30: #define PW_PIX 1 31: #define PW_WID 2 32: #define PW_ANIM 3
Pokud typ == PW_PIX, má být načtena pixmapa ze stringu v položce u.pixmap. Funkce pw_pix přidá do fronty údaj o načtení lokální pixmapy. pol.c 87: void pw_pix (char *nazev) 88: { 89: pw_alloc(); 90: 91: pospw->typ = PW_PIX; 92: pospw->u.pixmap = dupstr(nazev); 93: }
Pokud ve struktuře pol_widget položka typ == PW_WID, pak bude vytvořen widget se souřadnicemi podle podpoložky widget v položce u struktury pol_widget. Pixmapa mu je automaticky přidělena poslední. Widget je do fronty přidán funkcí pw_wid. pol_widget *pospw /*pol*/ : 169, 171, 177–179 void pw_alloc /*pol*/ (): 177–179 void pw_pix(): 177–178, 197 void pw_wid(): 178
177
31 Modul pol
Program kraluk pol.c
95: void pw_wid (int x, int y, float z) 96: { 97: pw_alloc(); 98: 99: pospw->typ = PW_WID; 100: pospw->u.widget.x = x; 101: pospw->u.widget.y = y; 102: pospw->u.widget.z = z; 103: rozdilz = z-y; 104: }
Funkce pw_xy přidá do fronty také widget, ale bude mít stejný rozdíl Y-ové a Z-kové souřadnice jako naposledy přidaný widget. Tento rozdíl si uchovávám v proměnné rozdilz. pol.c 35: static float rozdilz = 0; pol.c 106: void pw_xy (int x, int y) 107: { 108: pw_alloc(); 109: 110: pospw->typ = PW_WID; 111: pospw->u.widget.x = x; 112: pospw->u.widget.y = y; 113: pospw->u.widget.z = y+rozdilz; 114: }
Funkce pridej_pw přidá do fronty pol˙widgetů jednu pixmapu a jeden widget, což vlastně tvoří jeden ucelený prvek. pol.c 164: void pridej_pw (int x,int y, float z, char *nazev) 165: { 166: pw_pix(nazev); 167: pw_wid(x,y,z); 168: }
Poslední možný typ struktury pol_widget je PW_ANIM. Jakmile se toto objeví, jsou v položce u.widget animovaného widgetu. V příští položce fronty pak je použita položka u.anim, ve které jsou informace pro timer a počet políček animace. Nakonec jsou do položky u.pokranim ukládány postupně časy a pixmapy. Do každé takové položky se vejdou dva časy a dvě pixmapy. Pixmapa není ukládána jako pointer, ale jako číslo, kolikátá pixmapa to je. Číslo 0 znamená NULL, číslem 1 je určena naposledy přečtená pixmapa, číslem 2 pixmapa načtena před touto pixmapou, . . . Funkce pw_anim přidá do fronty jeden animovaný widget, tedy vše to, o čem jsem psal v předchozím odstavci. Má proměnný počet parametrů a počet prvků animace je dán počtem polí aniimace. Tyto parametry se od parametru prvpix střídají takto: číslo pixmapy, čas, číslo pixmapy, čas, . . ., číslo pixmapy, čas, −1. Seznam parametrů se tedy ukončí, když je napsáno −1. Dále funkce pw_anim přičte jedničku k položce pocetanim ve struktuře kq_policko. pol.c 116: void pw_anim (int x, int y, float z, float priorita, int opakovani, int prvpix, int prvcas, ...) 117: { 118: va_list vl; 119: int stav; 120: pol_widget *puvanim; 121: 122: aktupol->pocetanim++; 123: 124: pw_alloc(); 125: 126: pospw->typ = PW_ANIM; 127: pospw->u.widget.x = x; 128: pospw->u.widget.y = y; 129: pospw->u.widget.z = z; 130: void pw_xy(): 178, 192–194, 196–197 float rozdilz /*pol*/ (): 169, 171, 178 void pridej_pw(): 178, 191–197, 199–200 PW_ANIM: 169, 177–179 void pw_anim(): 178, 197–199
178
31 Modul pol 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: }
Program kraluk
pw_alloc(); pospw->u.anim.priorita = priorita; pospw->u.anim.opakovani = opakovani; pospw->u.anim.pocet = 0; if(prvpix < 0) warning("malo policek animace"); puvanim = pospw; va_start(vl, prvcas); stav = 0; while(prvpix >= 0){ puvanim->u.anim.pocet++; if(stav){ pospw->u.pokranim.pix2 = prvpix; pospw->u.pokranim.cas2 = prvcas; stav = 0; } else{ pw_alloc(); pospw->u.pokranim.pix1 = prvpix; pospw->u.pokranim.cas1 = prvcas; stav = 1; } prvpix = va_arg(vl, int); prvcas = va_arg(vl, int); } va_end(vl);
Při vstupu na políčko funkce pol_widgety projde frontu pw v políčku a provede ji. Na začátku je namallokováno pole animpole podle položky animpole. pol.h 79: kq_anim *animpole; pol.c 257: static void pol_widgety () 258: { 259: pol_widget *pom; 260: int pocetpixmap, pocetanim; 261: int x,y; float z; 262: float priorita, opakovani, pocet; 263: int i; 264: 265: if(aktupol->pocetanim) animpole = mymalloc(aktupol->pocetanim*sizeof(kq_anim)); 266: 267: pocetpixmap = pocetanim = 0; 268: for(pom = aktupol->pw; pom; pom = pom->next){ 269: switch(pom->typ){ 270: case PW_PIX: 271: nactikqXPM(pom->u.pixmap, 1); 272: pocetpixmap++; 273: break; 274: case PW_WID: 275: if(!pocetpixmap) warning("nebyla nactena pixmapa pred widgetem"); 276: vytvorwidget (pom->u.widget.x, pom->u.widget.y, pom->u.widget.z, prvpix, 1, -1); 277: break; 278: case PW_ANIM: 279: if(pocetanim >= aktupol->pocetanim){ 280: pocetanim++; 281: break; 282: } 283: x = pom->u.widget.x; void pol_widgety /*pol*/ (): 171–172, 179
kq_anim *animpole: 137, 139, 143, 147, 179–181
179
31 Modul pol
Program kraluk
284: y = pom->u.widget.y; 285: z = pom->u.widget.z; 286: 287: pom = pom->next; 288: if(!pom){ 289: warning("predcasne skoncene nacitani animace"); 290: break; 291: } 292: 293: priorita = pom->u.anim.priorita; 294: opakovani = pom->u.anim.opakovani; 295: animpole[pocetanim].pocet = pocet = pom->u.anim.pocet; 296: 297: if(pocet == 0) warning("animace ma nula policek"); 298: else{ 299: animpole[pocetanim].pix = (kq_pixmap **)mymalloc(pocet*sizeof(kq_pixmap *)); 300: animpole[pocetanim].casy = (unsigned int *)mymalloc(pocet*sizeof(unsigned int)); 301: } 302: 303: for(i = 0; i<pocet; i++){ 304: if(i%2){ 305: animpole[pocetanim].pix[i] = vylovpix(pom->u.pokranim.pix2, pocetpixmap); 306: animpole[pocetanim].casy[i] = pom->u.pokranim.cas2; 307: } 308: else{ 309: pom = pom->next; 310: if(!pom){ 311: warning("predcasne skoncene nacitani animace"); 312: break; 313: } 314: animpole[pocetanim].pix[i] = vylovpix(pom->u.pokranim.pix1, pocetpixmap); 315: animpole[pocetanim].casy[i] = pom->u.pokranim.cas1; 316: } 317: } 318: 319: if(pocet) startanimwid(&animpole[pocetanim], x, y, z, priorita, opakovani, 1, -1); 320: 321: 322: pocetanim++; 323: break; 324: 325: default: 326: warning("neznamy typ pol_widgetu"); 327: } 328: } 329: }
Tato funkce pro získání submapy z čísla pixmapy používa funkci vylovpix. pol.c 239: static kq_pixmap *vylovpix (int cislo, int pocetpix) 240: { 241: int i; 242: kq_pixmap *vysledek; 243: 244: if(cislo <= 0){ 245: if(cislo < 0) warning("zaporne cislo pixmapy"); 246: return NULL; 247: } 248: else{ 249: if(cislo > pocetpix) warning("prilis velke cislo pixmapy"); 250: vysledek = prvpix; 251: for(i=1; inext; 253: return vysledek; 254: } 255: } kq_pixmap *vylovpix /*pol*/ (): 180
180
32 Modul predmet
Program kraluk
Funkce free_animpole smaže animpole při odchodu z políčka.
32 Modul predmet Předmět, tedy struktura kq_predmet, spojuje postavy, slova a políčka. Tato struktura vypadá následovně: predmet.h 1: struct kq_predmet{ 2: unsigned int inv; 3: kq_word *slovo; 4: kq_policko *pol; 5: char *nazev; 6: char stav; 7: 8: int pix_x, pix_y; 9: float pix_z; 10: int sm_x, sm_y; 11: float sm_z; 12: kq_postava *post; 13: 14: kq_predmet *polnext; 15: 16: int Cislo; 17: kq_predmet *next; 18: };
Předmět má tři možnosti, kde může být. Buď může být v inventáři, na nějakém políčku (scéně) nebo také nemusí být nikde. V případě, že je předmět v inventáři, tak položka inv je nastavena na true. V modulech save a load pak položku inv použiju jako údaj o pořadí v inventáři. Toto pořadí je totiž důležité při zobrazení inventáře. Pokud inv je false, tak v položce pol je údaj o tom, na kterém políčku se předmět vyskytuje. O umístění na políčku pak rozhodují položky pix_x, pix_y, pix_z, sm_x, sm_y, sm_z. Předmět, který není nikde, pak má v položce pol uloženo NULL. Všechny vytvořené předměty jsou řazeny do seznamu pomocí položky next, který začíná proměnnou prvpredmet. Kromě toho jsou současně předměty řazeny do dalších seznamů pomocí položky polnext. Předměty nacházející se v inventáři jsou v seznamu začínajícím proměnnou inventar a předměty, které jsou na určitém políčku, jsou v seznamu začínajícím položkou predmety příslušného políčka. predmet.c 20: kq_predmet *inventar = NULL; 21: kq_predmet *prvpredmet = NULL;
Do správného seznamu pospojovaného položkou polnext zařadí předmět funkce zaradpredmet. predmet.c 63: static void zaradpredmet (kq_predmet *p) 64: { 65: kq_predmet **kam; 66: 67: if(p->inv){ 68: kam = &inventar; 69: if(p->slovo) p->slovo->kontext++; 70: } 71: else{ 72: if(!p->pol) return; 73: kam = &p->pol->predmety; 74: if(win && p->pol == aktupol) zobrazpredmet(p); 75: } 76: 77: p->polnext = *kam; 78: *kam = p; 79: }
Funkce vyradpredmet pak předmět z takového seznamu vyřadí. void free_animpole(): 147, 173 kq_predmet: 7, 87, 138–139, 142–143, 146, 148, 153–154, 168, 181–186, 190 kq_predmet *prvpredmet: 139, 142–143, 148, 181, 183, 187 kq_predmet *inventar: 142, 148, 181–182, 185–187 void zaradpredmet /*predmet*/ (): 181, 183 void vyradpredmet /*predmet*/ (): 182–183
181
32 Modul predmet
Program kraluk predmet.c
81: static void vyradpredmet (kq_predmet *p) 82: { 83: kq_predmet **odkud; 84: 85: if(p->inv){ 86: odkud = &inventar; 87: if(p->slovo) p->slovo->kontext--; 88: } 89: else{ 90: if(!p->pol) return; 91: odkud = &p->pol->predmety; 92: if(win && p->pol == aktupol) zmizpredmet(p); 93: } 94: 95: while(*odkud && *odkud != p) odkud = &(*odkud)->polnext; 96: if(!*odkud){ 97: warning("nepodarilo se vyradit predmet"); 98: return; 99: } 100: *odkud = p->polnext; 101: return; 102: }
Ve struktuře kq_predmet dále může být v položce slovo uloženo určité slovo (kq_word). Toto slovo má typ nastaven na OBJWORD a v položce informace je ukazatel zpátky na předmět. Dále je tomuto slovu zvýšen kontext o jedničku v případě, že je předmět v inventáři nebo na právě aktivním políčku. Po odebrání z inventáře nebo změně aktivního políčka kontext opět poklesne. Zásadní položkou předmětu je jeho nazev. Tento string nesmí být NULL a je používán jako: 1) název submapy, která je použita pro předmět. 2) název jednočlené animace postavy. 3) název pixmapy, která bude zobrazena při prohlížení inventáře. Funkce zmenprnazev změní název předmětu. Pokud je však předmět vyobrazen na aktuálním políčku, nezmění se, dokud se na toto políčko nevejde znovu. Pro okamžitou změnu předmětu je možné ho přezobrazit funkcí predmetpol. predmet.c 159: void zmenprnazev (kq_predmet *p, char *nazev) 160: { 161: free(p->nazev); 162: p->nazev = dupstr(nazev); 163: p->stav = !p->stav; 164: }
Tato funkce navíc změní položku stav. Tato položka struktury kq_predmet je při vytvoření předmětu false a ukazuje právě, zda byl změněn jeho název. Navíc stav ovlivňuje použitý output v inventáři. Funkce vytvorpredmet založí nový předmět, který není ani v inventáři ani na políčku. Do parametru nazev dostane název předmětu a do parametru slovo údaj, zda má tato funkce do předmětu přidat nové slovo. predmet.c 104: kq_predmet *vytvorpredmet (char *nazev, char slovo) 105: { 106: kq_predmet *vysledek; 107: 108: vysledek = (kq_predmet *)mymalloc(sizeof(kq_predmet)); 109: 110: vysledek->inv = 0; 111: vysledek->stav = 0; 112: vysledek->pol = NULL; 113: vysledek->nazev = dupstr(nazev); 114: if(slovo){ 115: vysledek->slovo = add_word(0); 116: vysledek->slovo->informace = pinpointer(vysledek); 117: vysledek->slovo->typ = OBJWORD; void zmenprnazev(): 182, 207, 211–212, 215–216, 222
182
void vytvorpredmet(): 182, 242
32 Modul predmet 118: 119: 120: 121: 122: 123: 124: }
Program kraluk
} vysledek->post = NULL; vysledek->next = prvpredmet; prvpredmet = vysledek; return vysledek;
Pro manipulaci s předměty dále existují tři funkce. Funkce predmetinv dá předmět na začátek inventáře. predmet.c 126: void predmetinv (kq_predmet *p) 127: { 128: vyradpredmet(p); 129: p->inv = 1; 130: zaradpredmet(p); 131: }
Funkce predmetpol dá předmět na určené políčko. Tato funkce dále dostane souřadnice, kde má být umístěna pixmapa v parametrech pix_x, pix_y a pix_z, a souřadnice, kde má být umístěna submapa v parametrech sm_x, sm_y, sm_z. Každý předmět tedy musí mít pixmapu i submapu. Souřadnice pix_x a pix_y nejsou souřadnicemi od levého horního rohu obrázku, ale od levého horního rohu hlavní mapy. Skutečné souřadnice tedy jsou map_xb+pix_x, map_yb+pix_y. predmet.c 141: void predmetpol (kq_predmet *p, kq_policko *pol, 142: int pix_x, int pix_y, float pix_z, 143: int sm_x, int sm_y, float sm_z) 144: { 145: if(!pol) warning("predmetpol: pol == NULL"); 146: 147: vyradpredmet(p); 148: p->inv = 0; 149: p->pol = pol; 150: p->pix_x = pix_x; 151: p->pix_y = pix_y; 152: p->pix_z = pix_z; 153: p->sm_x = sm_x; 154: p->sm_y = sm_y; 155: p->sm_z = sm_z; 156: zaradpredmet(p); 157: }
Funkce predmetnull vrátí předmět do počátečního stavu, kde předmět není ani v inventáři ani na žádném políčku. predmet.c 133: void predmetnull (kq_predmet *p) 134: { 135: if(!p->inv && !p->pol) return; 136: vyradpredmet(p); 137: p->inv = 0; 138: p->pol = NULL; 139: }
V případě, že se předmět objeví na aktuálním políčku, je do jeho položky post vytvořena lokální postava bez timeru, které se přiřadí jednoprvková animace podle položek nazev, pix_x a pix_y, Z-ková souřadnice podle položky pix_z a submapa podle položek nazev, sm_x, sm_y a sm_z. Navíc je třeba přičíst kontext ke slovu předmětu. Tohle všechno provede funkce zobrazpredmet. predmet.c 24: static void zobrazpredmet (kq_predmet *p) 25: { 26: if(p->post) warning("zobrazovany predmet uz je zobrazeny"); 27: 28: if(p->slovo) p->slovo->kontext++; 29: p->post = vytvorpost(0,0,0,0,0,1,0); void predmetinv(): 183, 185, 207, 213–216 void predmetpol(): 182–183, 215, 242 void predmetnull(): 183, 210, 214–215, 218, 221, 223–224 void zobrazpredmet /*predmet*/ (): 181, 183–184
183
32 Modul predmet 30: 31: 32: 33: 34: 35: }
Program kraluk
p->post->barvy = 0; p->post->zdi = 0; zmenanip(p->post, nactianip(-p->pix_x, -p->pix_y, p->nazev,1,0,1,0,1)); p->post->z = p->pix_z; post_submap(p->post, p->nazev, -p->sm_x, -p->sm_y, p->sm_z);
Když se zaktivní určité políčko, je žádoucí, aby na něm byly takto zaktivněny všechny jeho předměty. Při vykreslování políčka je proto zavolá funkce zobrazpredmety. predmet.c 37: void zobrazpredmety () 38: { 39: kq_predmet *pom; 40: 41: for(pom = aktupol->predmety; pom; pom = pom->polnext) 42: zobrazpredmet(pom); 43: }
Podobně v případě, že předmět zmizí z aktuálního políčka, je třeba položku post z předmětu opět vymazat a kontext zpátky odečíst. To dělá funkce zmizpredmet. predmet.c 45: static void zmizpredmet (kq_predmet *p) 46: { 47: if(p->slovo) p->slovo->kontext--; 48: if(p->post) znicpost(p->post); 49: else warning("predmet pro zmizeni neni zobrazeny"); 50: p->post = NULL; 51: }
Funkce zmizpredmety je zavolána při odchodu z políčka. Tato funkce však nepoužívá funkci zmizpredmet, protože budou postavy předmětů automaticky zničeny díky své lokálnosti. Takže funkce zmizpredmety jen do položky post dosadi NULL a sníži kontext. predmet.c 53: void zmizpredmety () 54: { 55: kq_predmet *pom; 56: 57: for(pom = aktupol->predmety; pom; pom = pom->polnext){ 58: pom->post = NULL; 59: if(pom->slovo) pom->slovo->kontext--; 60: } 61: }
Následující dvě funkce jenom zobrazí vyskakovací okno s hláškou týkající se předmětů. Funkce uzmaspredmet vyskočí s hláškou s labelíkem _uz mas, kde je # nahrazen názvem slova daného předmětu. predmet.c 166: void uzmaspredmet (kq_predmet *p) 167: { 168: popupwarning("_uz mas", p->slovo->nazev); 169: }
Funkce sebralspredmet vyskočí s hláškou s labelíkem _bere a slovem daného předmětu. predmet.c 171: void sebralspredmet (kq_predmet *p) 172: { 173: popupoutput("_bere", p->slovo, DEF_POP_SIRKA, DEF_POP_VYSKA, DEF_POP_X, DEF_POP_Y); 174: }
Funkce seberpredmet dostane předmět, který má sebrat. Tato funkce se pokusí sebrat předmět z políčka do inventáře. V případě, že předmět nebyl na aktuálním políčku, vrátí tato funkce −1. Pokud se mu povede předmět sebrat, vrátí 1. Nulu vrátí v případě, že souřadnice, které funkce dostala, jsou příliš daleko od předmětu. V takovém případě navíc vyskočí s hláškou pod labelíkem _too far. Že jsou souřadnice příliš daleko, program pozná podle toho, že v submapě příslušící předmětu, tyto souřadnice void zobrazpredmety(): 171–172, 184 void zmizpredmet /*predmet*/ : 182, 184 void zmizpredmety(): 173, 184 void uzmaspredmet: 184–185, 216 void sebralspredmet(): 184–185, 216 char seberpredmet(): 185
184
32 Modul predmet
Program kraluk
nejsou v barvě dosahpredmet. Pokud dosahpredmet == NULL, nemůže situace, že bych byl příliš daleko, vůbec nastat. predmet.c 22: kq_color *dosahpredmet = NULL; predmet.c 176: char seberpredmet (kq_predmet *p, int x, int y) 177: { 178: if(p->inv){ 179: uzmaspredmet(p); 180: return 0; 181: } 182: if(!p->post) return -1; 183: if(dosahpredmet && 184: (!p->post->submap || 185: smpixel(p->post->submap, x, y) != dosahpredmet)){ 186: popup_info("_too far"); 187: return 0; 188: } 189: 190: predmetinv(p); 191: sebralspredmet(p); 192: 193: return 1; 194: }
Funkce seberslovo zavolá funkci seberpredmet s parametrem získaného ze slova předmětu, které dostane. Souřadnice určí podle ovlpost. predmet.c 196: char seberslovo (kq_word *slovo) 197: { 198: if(!slovo || !ovlpost || slovo->typ != OBJWORD 199: || slovo->informace.typ != PINPOINTER){ 200: warning("seberslovo selhalo"); 201: return 0; 202: } 203: 204: return seberpredmet((kq_predmet *)(slovo->informace.u.p), ovlpost->x, ovlpost->y); 205: }
Funkce ukazinv zobrazí inventář jako výběr. Když na nějaké položce hráč zmáčkne enter, smaže výběr a zobrazí příslušnou položku inventáře. Potom opět zobrazí inventář ve stejném místě jako ho ukončil. Název položky inventáře si bere z outputu podle slova předmětu. V případě, že slovo má stav false, použije labelík _inv a v případě, že slovo má stav true, použije labelík __inv. Nadpis inventáře si vytáhne z labelíku _inventar. predmet.c 238: void ukazinv () 239: { 240: int i, j, pos; 241: kq_predmet *pom; 242: char **vyber; 243: char *label; 244: 245: if(!inventar){ 246: popupoutput("_empty inv", NULL, DEF_POP_SIRKA, DEF_POP_VYSKA, 247: DEF_POP_X, DEF_POP_Y); 248: return; 249: } 250: 251: i = 1; 252: for(pom = inventar; pom; pom = pom->polnext) i++; 253: vyber = mymalloc(sizeof(char *) * i); 254: i = 0; 255: for(pom = inventar; pom; pom = pom->polnext){ 256: if(pom->stav) label = "__inv"; kq_color *dosahpredmet: 185, 207–211, 213–215, 217, 240–241 void ukazinv(): 20, 185
185
char seberslovo(): 185, 215–216
32 Modul predmet 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: }
Program kraluk
else label = "_inv"; vyber[i] = outputstring(label, pom->slovo); if(!vyber[i]) vyber[i] = pom->nazev; i++; } vyber[i] = NULL; i = 0; pos = 0; for(;;){ i = popupselect(DEF_POP_SIRKA, DEF_POP_VYSKA, DEF_POP_X, DEF_POP_Y, outputstring("_inventar", NULL), vyber, i, &pos); if(i < 0) break; pom = inventar; for(j = 0; jpolnext; if(!koukniinv(pom)) break; } free(vyber);
Funkce koukniinv zobrazí jeden předmět. Načte si pixmapu podle názvu předmětu, kterou zobrazí v horní části okna, a ve spodní části okna zobrazí text o tom předmětu. Část výšky okna, do které se zobrazí pixmapa, je UINVPOMER. Text se pak zobrazí s výškou 1-UINVPOMER a šířkou UINVSIRKA. Jako labelík použije _inv_look v případě, že stav předmětu je false, nebo __inv_look v případě, že stav předmětu je true. Dále při vyhledání vhodného outputu použije slovo předmětu. Pro zobrazení pixmapy funkce nevyužívá modul widget, ale zobrazí ji přímo jako okno, takže nemusí přesně pasovat na pixelovou mřížku na pozadí. predmet.c 207: char koukniinv (kq_predmet *p) 208: { 209: kq_pixmap *pix; 210: Window w; 211: int x, y, sirka, vyska; 212: char *label, navrat; 213: 214: pix = nactikqXPM(p->nazev, 0); 215: sirka = pix->PIX_SIR*ratio; 216: vyska = pix->PIX_VYS*ratio; 217: x = (win_sirka-sirka)/2; 218: y = (win_vyska*UINVPOMER-vyska)/2; 219: w = XCreateSimpleWindow(display, win, x, y, sirka, vyska, 0, 220: BlackPixel(display,screen), 221: WhitePixel(display,screen)); 222: XShapeCombineMask (display, w, ShapeBounding, 223: 0, 0, pix->akanal, ShapeSet); 224: XSetWindowBackgroundPixmap(display, w, pix->barvy); 225: XMapWindow(display, w); 226: 227: if(p->stav) label = "__inv_look"; 228: else label = "_inv_look"; 229: navrat = popupoutput(label, p->slovo, UINVSIRKA, 1-UINVPOMER, 0.5, 1); 230: 231: XDestroyWindow(display, w); 232: freekqPixmap(pix); 233: 234: return navrat; 235: }
Funkce deleteApredmets smaže všechny předměty. Používá se při načítání pozice nebo při restartu. predmet.c 276: void deleteApredmets () 277: { 278: kq_predmet *pom, *pomo; 279: void koukniinv(): 186 float UINVPOMER: 11, 186 deleteApredmets(): 148, 186, 188
186
float UINVSIRKA: 11, 186
void
33 Modul misc 280: 281: 282: 283: 284: 285: 286: 287: 288: }
Program kraluk
for(pom = prvpredmet; pom; pom = pomo){ pomo = pom->next; if(!pom->inv && pom->pol) pom->pol->predmety = NULL; free(pom->nazev); free(pom); } prvpredmet = NULL; inventar = NULL;
33 Modul misc V tomto modulu mám iniciační a ukončovací funkce. Kód spouštěný na začátku programu se dá rozdělit do tří částí. V programu by měly být popořadě spuštěny funkce kql_defaults, kql_init a kql_start. Není třeba psát nic před funkci kql_defaults a už vůbec není třeba nic psát za funkci kql_start, protože tato funkce běží do konce programu. Zmíněné tři části tedy jsou mezi kql_defaults a kql_init, potom mezi kql_init a kql_start a nakonec v restartující funkci. Restartující funkce je předána funkci kql_start. V první části je možné předefinovat některé hodnoty z modulu defaults. Také je dobré v této části nastavit možné rychlosti hry funkcí setFPSs. V druhé části pak je možné přenastavit některé klávesové zkratky, registrovat některé proměnné pro moduly save a load, založit políčka a barvy a načíst zafixované pixmapy a animace postav. Tyto pixmapy tak budou mít už nastavené správné ratio. Do restartující funkce pak patří vše, co musí být při restartu přenastaveno. Nejprve by mělo být nastaveno políčko pomocí funkce set_pol. Také zde mohou být vytvořeny postavy, widgety, nezafixované pixmapy a animace, . . . Kromě toho však sem patří i funkce zabývající se inputem, tedy add_word a add_sent. To proto, že je zde třeba založit předměty a přitom mohou být tyto funkce také použity. Funkce kql_init přijme parametry argc, argv příkazového řádku, aby na ně mohla nasměrovat gargc a gargv (globální varianty téhož). Tím k těmto informacím budou mít přístup všechny funkce. Dále tato funkce inicializuje locales, pokusí se nastavit LC_CTYPE na cs_CZ.ISO8859-2. Možnost práce programu v UTF-8 kódování není implementována, protože pro vykreslování stringů je použita obyčejná funkce XDrawString z Xlibu a nikoli její složitější verze podporující prostřednictvím locales UTF-8 fonty. Dále je ve funkci kql_init navázána komunikace s Xserverem a jsou iniciovány datové struktury programu. Nakonec se voláním fukce load_conf pokusí obnovit původní stav konfigurace programu uložený při předchozím ukončení programu do souboru ~/.kraluk/lastpos. misc.c 36: void kql_init (int argc, char **argv) 37: { 38: struct stat buf; 39: 40: gargc = argc; 41: gargv = argv; 42: srand(time(0)); 43: inithome(); 44: reloadmap(); 45: if(setlocale(LC_CTYPE,"cs_CZ.ISO8859-2") == NULL) 46: warning("could not set cs_CZ.ISO8859-2 as LC_CTYPE locale"); 47: if(stat(DATADIR_LOCAL, &buf) == 0) DATADIR = DATADIR_LOCAL; 48: initX(); 49: pinnull.typ = PINNULL; 50: inithash(); 51: initbindings(); 52: init_sl(); 53: 54: nactijazyky(); 55: aktulang = prvlang; 56: load_conf(); 57: }
Funkce kql_start ukončí inicializaci a roztočí loop. Tato funkce navíc v parametru dostane a spustí restartující funkci. void kql_init(): 8, 12, 26, 159, 187, 190
void kql_start(): 187–188, 190
187
33 Modul misc
Program kraluk misc.c
59: void kql_start (void (*r_func)()) 60: { 61: char *fullname; 62: struct stat buf; 63: 64: restart_func = r_func; 65: 66: if(aktupol) aktupol->locbarva = prvbarva; 67: if(r_func) r_func(); 68: finishws(); 69: 70: startlang(); 71: 72: if(SAVELAST){ 73: fullname = joinstrings(homedir, "/", SAVELAST, NULL); 74: if(stat(fullname, &buf) == 0) load_all(SAVELAST); 75: free(fullname); 76: } 77: 78: if(!win){ 79: prvnipol(); 80: popup_info("_about"); 81: } 82: initklav(); 83: loop(); 84: }
Restartující funkci dosadí do proměnné restart_func. misc.h 6: void (*restart_func)();
Ve funkci kql_restart restartuji hru, tj. vymažu veškeré paměťové struktury postupně budované během hry a spustím restartující funkci. misc.c 86: void kql_restart () 87: { 88: if(!restart_func) return; 89: 90: autoreloadmap = 0; 91: 92: deleteApixmaps(); 93: deleteAwidgets(); 94: deleteAsubmaps(); 95: deleteAanips(); 96: deleteAposts(); 97: deleteAtimers(); 98: deleteApredmets(); 99: aktulslovo = prvulslovo; 100: 101: restart_func(); 102: 103: vykreslipol(); 104: }
Konečně funkce kql_exit se postará o správné ukončení programu. Tato funkce uloží nastavení a pozici, uvolní veškeré zdroje X window systému a skončí s nulovou návratovou hodnotou. misc.c 106: void kql_exit () 107: { 108: if(SAVELAST) save_all(SAVELAST); 109: save_conf(); 110: XUnloadFont(display, font_info->fid); 111: XUnloadFont(display, popup_small_font->fid); 112: if(popup_big_font != popup_small_font) 113: XUnloadFont(display, popup_big_font->fid);
void *restart_func: 188
void kql_restart(): 21, 188, 214
188
void kql_exit(): 20, 188, 217
34 Modul kql
Program kraluk
114: XFreeGC(display, text_gc); 115: XCloseDisplay(display); 116: exit(0); 117: }
34 Modul kql Abych v implementaci příběhu nemusel mít napsáno #include třiceti tří hlavičkových souborů předchozích modulů a pak ještě několika standardních knihoven, shrnuji to všechno do souboru kql.h. Tento modul tedy má jen svůj hlavičkový soubor, který vypadá takto: kql.h 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36:
#include<stdio.h> #include<stdlib.h> #include<string.h> #include "types.h" #include "defaults.h" #include "warning.h" #include "home.h" #include "filer.h" #include "pin.h" #include "list.h" #include "mystring.h" #include "X.h" #include "pixmap.h" #include "window.h" #include "hash.h" #include "keyboard.h" #include "edit.h" #include "widget.h" #include "timer.h" #include "animwid.h" #include "bindings.h" #include "loop.h" #include "color.h" #include "map.h" #include "post.h" #include "autopost.h" #include "pol.h" #include "input.h" #include "popup.h" #include "output.h" #include "languages.h" #include "predmet.h" #include "save.h" #include "load.h" #include "gsl.h" #include "misc.h"
B
Implementace příběhu
Moduly této části nemají své H-čkové soubory jako v části předchozí, ale všechny použité globální proměnné jsou v souboru kraluk.h. Tento soubor je téměř jediný, který jednotlivé moduly z této části načítají.
35 Modul version Jediný další H-čkový soubor, co je načítaný v této části C-čkovými soubory, je soubor version.h. Tento soubor obsahuje definici VERSION, abych mohl v modulu kraluk vypsat na terminál aktuální verzi. VERSION: 190
189
36 Modul kraluk
Program kraluk version.h
1: #define VERSION "0.8.2"
Tento soubor needituji, nýbrž ho automaticky generuji ze souboru version pomocí make. version 1: 0.8.2 Makefile 49: version.h: version 50: echo "#define VERSION" \"‘cat version‘\" > version.h
Soubor version je rovněž čtený TEXem při zpracování dokumentace, takže stejné číslo version jako v programu se objeví i vpravo nahoře u nadpisu dokumentace.
36 Modul kraluk Tento modul obsahuje funkci, na kterou určitě všichni netrpělivě čekáte. Funkci main. V této funkci volám funkce kql_defaults, kql_init a kql_start. Více o těchto funkcích a o tom, co má být mezi nimi, je řečeno v modulu misc. kraluk.c 21: int main (int argc, char **argv) 22: { 23: printf("This is kraluk version %s\n", VERSION); 24: 25: kql_defaults(); 26: identstring = "Kralovsky ukol 1"; 27: setFPSs(1000.0, 700.0, 400.0, 200.0, 100.0, 70.0, -50.0, 25.0, 15.0, 28: 9.0, 6.0, 3.0, 2.0, 1.5, 0.); 29: kql_init(argc, argv); 30: 31: registrujpf(); // registruji promenne a funkce pro moduly save a load 32: nactigbarvy(); // nastavim globalni barvy 33: nactianipy(); // nactu fixovane animace postav 34: nastavpolicka(); // nastavim policka (scena) hry 35: 36: kql_start(&restart); 37: 38: return 0; 39: }
Funkci kql_start je předána jakožto restarující funkce restart. Funkce restart mimo jiné vytvoří postavu panacek, což je postava, kterou hráč většinu času hry ovládá. kraluk.c 4: static void restart () 5: { 6: set_pol(pol[4][3]); 7: 8: initprom(); // nastavim pocatecni hodnoty promennym 9: vetyslova(); // nastavim slova a vety 10: vytvorpredmety(); // zalozim predmety (kq_predmet) 11: 12: 13: // vytvorim panacka: 14: 15: panacek = vytvorpost(22, 85, DOLU, 3, 0, 0, 0); 16: zmenanip(panacek, chozeni); 17: ovlpost = panacek; 18: normal_z(panacek, NULL, NULL); 19: }
37 Modul kra polic Zde řeším políčka (scény hry). Políčka hlavní torusoidní mapy jsou v dvourozměrném poli pol. Scéna v levém horním rohu obrázku je pol[0][0], scéna v levém dolním rohu obrázku je pol[0][6], scéna v pravém horním rohu obrázku je pol[7][0] a scéna v pravém dolním rohu obrázku je pol[7][6]. int main(): 7–8, 190, 246 void restart(): 7, 21, 190, 246 kq_postav *panacek: 190, 204, 206–219, 221–226, 228, 230–232, 234, 236–241, 244 kq_policko **pol: 190–196, 199–202, 204–205, 207–211, 214–216, 218, 220–221, 223–227, 229, 232–233, 237–239, 242
190
37 Modul kra polic
Program kraluk kraluk.h
16: kq_policko *pol[8][7];
Na obrázku je dále svislá černá čára, která odděluje výše popsanou mapu od ostatních políček. Mezi těmito ostatními políčky je dole interiér hradu, jehož pravá část je uložena do proměnné vzamku1 a jeho levá část je uložena v proměnné vzamku2. Vlevo nad interiérem zámku je interiér dřevěné chaloupky, který je uložený v proměnné vdrevchal. Dále zde je několik propojených políček skály. Skála, na kterou se panáček teleportuje (vlevo dole) je políčko skala1, Skála, na které je na začátku srolovaný žebřík (vpravo nahoře), je skala3 a mezi nimi je skala2. Pod skálou jsou políčka z žebříkem. To spodní je skal_zebr1 a to horní je skal_zebr2. Další čtveřice spojených nepopsaných políček jsou políčka v hlubokém podzemí. Políčko, kde je vidět brána do pekla, je peklbrana. Vnitřek pekla s velkým kotlem je políčko peklo. Na peklo navazuje políčko schody1 a na toto políčko pak navazuje políčko schody2. Z políčka schody2 už se pak dá dostat na pol[0][0]. Poslední nepopsané políčko je políčko, na kterém jsou dva lvi. Toto políčko je uloženo v proměnné lvi.
Hlavní funkcí tohoto modulu je funkce nastavpolicka, která při startu programu vytvoří, nastaví a propojí všechna políčka (scény) ve hře. kra_polic.c 3: void nastavpolicka () 4: { 5: pol_odchfunc = nullujznak; 6: 7: pol[0][0] = newpol("Mapa0x0", "Plocha0x0", 2,0,1,40); 8: pridej_pw( 1, 60, 200, "skala0x0.1"); 9: pridej_pw(33, 0, 12, "skala0x0.2"); 10: 11: pol[1][0] = newpol("Mapa1x0", "Plocha1x0", 2,0,1,40); 12: pol[1][0]->odchfunc = opravvodu; 13: pridej_pw(0,0,60, "skala1x0"); 14: pridej_pw(66,47,19, "trava1"); 15: pridej_pw(76,61,33, "trava2"); 16: pridej_pw(56,81,53, "trava3"); kq_policko *vzamku1: 199–200, 225 kq_policko *vzamku2: 200, 217 kq_policko *vdrevchal: 199, 216, 224, 242 kq_policko *skala1: 196, 199, 221, 231 kq_policko *skala3: 197, 199, 209, 215, 230–231, 242 kq_policko *skala2: 197, 199, 230–231 kq_policko *skal_zebr1: 199, 204–205, 223, 230–231, 234 kq_policko *skal_zebr2: 199, 204–205, 209, 230–231 kq_policko *peklbrana: 199, 224 kq_policko *peklo: 191, 199, 203, 212, 224 kq_policko *schody1: 199, 223 kq_policko *schody2: 191, 199, 223–224 kq_policko *lvi: 199, 213, 224, 237–239, 242 void nastavpolicka(): 190–191
191
37 Modul kra polic 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84:
Program kraluk
pridej_pw(68,99,71, "trava4"); pridej_pw(64,117,89, "trava5"); pw_xy(48,135); pridej_pw(176,45,17, "trava6"); pridej_pw(194,56,28, "trava7"); pridej_pw(180,70,42, "trava8"); pridej_ps(&voda); pol[2][0] = newpol("Mapa2x0", "Plocha2x0", 2,0,1,40); pridej_pw(26,4,38, "strom2x0"); pridej_ps(&strom); pridej_ps(&voda); pridej_ps(&tresne); pol[3][0] = newpol("Mapa3x0", "Plocha3x0", 2,0,1,40); pridej_pw(8,109,95, "kytky"); pridejbarvu("#662B00", 1)->prichfunc = bachakytky; pridej_ps(&voda); pol[4][0] = newpol("Mapa4x0", "Plocha4x0", 2,0,1,40); kq_color *voda4; voda4 = pridejbarvu("#2A00FF", 0); voda4->prichfunc = plave; voda4->odchfunc = sucho; pridej_ps(&voda); pol[5][0] = newpol("Mapa5x0", "Plocha5x0", 2,0,1,40); pridej_pw(18,0,120, "mrak"); kq_color *telebarva; telebarva = pridejbarvu("#009543", 0); telebarva->prichfunc = &telestart; telebarva->odchfunc = &teleend; pol[6][0] = newpol("Mapa6x0", "Plocha6x0", 2,0,1,40); pridej_pw(16,42,35, "balvan1"); pridej_pw(118,30,25, "balvan2"); pridej_pw(6,126,116, "balvan3"); pridej_pw(60,94,90, "balvan4"); pridej_pw(144,80,77, "balvan5"); pol[7][0] = newpol("Mapa7x0", "Plocha7x0", 2,0,1,40); pol[7][0]->prichfunc = start_jp; pol[0][1] = newpol("Mapa0x1", "Plocha0x1", 2,0,1,40); pridej_pw(0,0,1000, "skala0x1"); pol[0][1]->prichfunc = prichzebr; pol[0][1]->odchfunc = odchzebr; pol[1][1] = newpol("Mapa1x1", "Plocha1x1", 2,0,1,40); pridej_pw(40,14,53, "chaloupka1"); pridej_pw(99,14,86, "chaloupka2"); pridej_ps(&dvere); pol[2][1] = newpol("Mapa2x1", "Plocha2x1", 2,0,1,40); pol[2][1]->prichfunc = prich_jezin; pol[2][1]->odchfunc = nullosobu; pridej_ps(&smolicek); pridej_ps(&jezinky); pridej_pw(68,82,63, "parez"); pol[3][1] = newpol("Mapa3x1", "Plocha3x1", 2,0,1,40); pol[3][1]->prichfunc = prich_krk; pol[3][1]->odchfunc = null_krk; pridej_pw( 95,93,101, "proptaky"); pw_xy( 62,77); pw_xy( 38,59); pw_xy( 16,38); pw_xy(173,42);
192
37 Modul kra polic 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152:
Program kraluk
pw_xy(150,55); pw_xy(126,76); pridej_ps(&krkavci); pol[4][1] = newpol("Mapa4x1", "Plocha4x1", 2,0,1,40); pol[4][1]->prichfunc = start_jp; pridej_pw(4,17,104, "strom4x1.1"); pridej_pw(164,18,85, "strom4x1.2"); pridej_pw(66,0,35, "strom4x1.3"); pridej_ps(&strom); pol[5][1] = newpol("Mapa5x1", "Plocha5x1", 2,0,1,40); pol[5][1]->prichfunc = prich_bohd; pol[5][1]->odchfunc = odch_bohd; pridej_pw(41,16,90, "drevchal"); pridej_pw(82,104,95, "zidle"); pridej_ps(&dvere); pol[6][1] = newpol("Mapa6x1", "Plocha6x1", 2,0,1,40); pridej_pw( 12, 40,13, "trava6x1.1"); pw_xy( 46, 50); pw_xy( 79, 45); pw_xy(143, 48); pw_xy(190, 46); pw_xy(116, 63); pw_xy( 15, 92); pw_xy( 97, 90); pw_xy(155, 92); pw_xy(195, 98); pw_xy( 56, 111); pw_xy(181, 119); pw_xy( 29, 139); pw_xy(136, 142); pridej_pw( 15, 71, 44, "trava6x1.2"); pw_xy( 71, 72); pw_xy(167, 65); pw_xy( 56, 87); pw_xy(125, 107); pw_xy( 21, 116); pw_xy( 78, 126); pw_xy(103, 139); pridej_pw(200,88,56, "skala6x1"); pol[7][1] = newpol("Mapa7x1", "Plocha7x1", 2,0,1,40); pridej_pw(0,0,58, "skala7x1"); pol[0][2] = newpol("Mapa0x2", "Plocha0x2", 2,0,1,40); pol[0][2]->odchfunc = opravvodu; pridej_ps(&voda); pol[1][2] = newpol("Mapa1x2", "Plocha1x2", 2,0,1,40); pridej_pw( 61, 60, 29, "trava1x2.1"); pridej_pw(127, 61, 30, "trava1x2.2"); pridej_pw( 90, 91, 60, "trava1x2.3"); pridej_pw( 50, 118, 91, "trava1x2.4"); pw_xy(109, 118); pridej_pw( 81, 120, 93, "trava1x2.5"); pw_xy(134, 118); pol[2][2] = newpol("Mapa2x2", "Plocha2x2", 2,0,1,40); pol[2][2]->odchfunc = opravvodu; pol[2][2]->prichfunc = prich_jelen; pridej_ps(&voda); pridej_ps(&jelen); pol[3][2] = newpol("Mapa3x2", "Plocha3x2", 2,0,1,40); pridej_ps(&voda);
193
37 Modul kra polic 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220:
Program kraluk
pol[4][2] = newpol("Mapa4x2", "Plocha4x2", 2,0,1,40); pridej_pw(141, 39, 25, "ker4x2"); pridej_ps(&voda); pol[5][2] = newpol("Mapa5x2", "Plocha5x2", 2,0,1,40); pol[5][2]->odchfunc = opravvodu; pridej_ps(&voda); pol[6][2] = newpol("Mapa6x2", "Plocha6x2", 2,0,1,40); pol[6][2]->odchfunc = opravvodu; pridej_pw( 15, 30, 3, "trava1"); pw_xy(190, 36); pw_xy( 51, 43); pw_xy( 73, 139); pridej_pw( 63, 72, 45, "trava2"); pw_xy(163, 54); pw_xy(102, 84); pw_xy( 16, 60); pridej_pw(143, 37, 10, "trava3"); pw_xy( 94, 58); pw_xy(130, 54); pridej_pw(134, 78, 51, "trava4"); pw_xy( 11, 109); pw_xy( 88, 29); pridej_pw( 63, 109, 82, "trava5"); pw_xy(169, 29); pw_xy(102, 116); pridej_pw( 33, 89, 62, "trava6"); pw_xy( 34, 129); pw_xy(194, 62); pridej_ps(&voda); pol[7][2] = newpol("Mapa7x2", "Plocha7x2", 2,0,1,40); pridej_ps(&voda); pol[0][3] = newpol("Mapa0x3", "Plocha0x3", 2,0,1,40); pol[0][3]->odchfunc = opravvodu; pridej_ps(&voda); pol[1][3] = newpol("Mapa1x3", "Plocha1x3", 2,0,1,40); pridej_pw( 90, 5, 101, "strom1x3.1"); pridej_pw( 6, 13, 103, "strom1x3.2"); pridej_pw(145, 5, 70, "strom1x3.3"); pridej_pw( 47, 1, 66, "strom1x3.4"); pridej_pw(171, 5, 37, "strom1x3.5"); pridej_pw(126, 16, 49, "strom1x3.6"); pridej_pw( 83, 13, 46, "strom1x3.7"); pridej_pw( 38, 5, 32, "strom1x3.8"); pridej_ps(&strom); pol[2][3] = newpol("Mapa2x3", "Plocha2x3", 2,0,1,40); pol[2][3]->odchfunc = opravvodu; pridej_pw(79, 98, 77, "most"); most_col = pridejbarvu("#808080", 0); most_col->prichfunc = &prich_most; most_col->odchfunc = &odch_most; pridej_psm(39, 58, 1, "most", 1, &most_sm); pridej_ps(&voda); pol[3][3] = newpol("Mapa3x3", "Plocha3x3", 2,0,1,40); pridej_pw(21, 1, 74, "hrad_l"); pol[4][3] = newpol("Mapa4x3", "Plocha4x3", 2,0,1,40); pridej_pw( 0, 1, 74, "hrad_p"); pridej_pp(27, 74, 0, 0, &dvere_post, 0, 0, 74.1, NULL, 12, 10, 0, "dvere_h", 9, 38, 46, 0, 1, 0);
194
37 Modul kra polic 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288:
Program kraluk
pridej_ps(&dvere); pol[5][3] = newpol("Mapa5x3", "Plocha5x3", 2,0,1,40); pol[5][3]->odchfunc = opravvodu; pridej_ps(&voda); pol[6][3] = newpol("Mapa6x3", "Plocha6x3", 2,0,1,40); pol[6][3]->odchfunc = opravvodu; pridej_ps(&voda); pol[7][3] = newpol("Mapa7x3", "Plocha7x3", 2,0,1,40); pridej_pw( 7, 14, 85, "sluj_fg"); pridej_pw( 43, 52, 29, "sluj_bg"); pridej_pw(135, 74, 62, "bobes"); pridej_pw( 63, 102, 0, "dira_fg"); pridej_ps(&bobes); pridej_ps(&muz); pridej_ps(&osoba); pol[0][4] = newpol("Mapa0x4", "Plocha0x4", 2,0,1,40); pol[0][4]->odchfunc = opravvodu; pridej_pw(94, 63, 54, "ker0x4"); pridej_ps(&voda); pol[1][4] = newpol("Mapa1x4", "Plocha1x4", 2,0,1,40); pridej_pw(66, 100, 92, "ker1x4.1"); pridej_pw(82, 67, 57, "ker1x4.2"); pridej_pw(68, 30, 21, "ker1x4.3"); pol[2][4] = newpol("Mapa2x4", "Plocha2x4", 2,0,1,40); pol[2][4]->odchfunc = opravvodu; pridej_pw(15, 10, 96, "strom2x4"); pridej_ps(&strom); pridej_ps(&voda); pol[3][4] = newpol("Mapa3x4", "Plocha3x4", 2,0,1,40); pol[3][4]->odchfunc = opravvodu; pridej_ps(&voda); pol[4][4] = newpol("Mapa4x4", "Plocha4x4", 2,0,1,40); pridej_ps(&voda); pol[5][4] = newpol("Mapa5x4", "Plocha5x4", 2,0,1,40); pol[5][4]->odchfunc = opravvodu; pridej_ps(&voda); pol[6][4] = newpol("Mapa6x4", "Plocha6x4", 2,0,1,40); pol[6][4]->odchfunc = opravvodu; pridej_pw(122, 47, 38, "tyc6x4"); pridej_ps(&voda); pol[7][4] = newpol("Mapa7x4", "Plocha7x4", 2,0,1,40); pridej_ps(&voda); pol[0][5] = newpol("Mapa0x5", "Plocha0x5", 2,0,1,40); pridej_pw(40, 29, 28, "ker0x5.1"); pridej_pw(61, 67, 66, "ker0x5.2"); pridej_pw(81, 93, 96, "ker0x5.3"); pol[1][5] = newpol("Mapa1x5", "Plocha1x5", 2,0,1,40); pridej_pw(116, 5, 56, "strom1x5"); pridej_ps(&strom); pol[2][5] = newpol("Mapa2x5", "Plocha2x5", 2,0,1,40); pol[2][5]->odchfunc = opravvodu; pridej_ps(&voda); pol[3][5] = newpol("Mapa3x5", "Plocha3x5", 2,0,1,40);
195
37 Modul kra polic 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356:
Program kraluk
pol[3][5]->odchfunc = opravvodu; pridej_ps(&voda); pol[4][5] = newpol("Mapa4x5", "Plocha4x5", 2,0,1,40); pridej_pw(12, 8, 200, "palmlist"); pridej_pw(59, 35, 98, "palmkmen"); pridejbarvu("#662B00", 0)->prichfunc = padejkokos; pol[5][5] = newpol("Mapa5x5", "Plocha5x5", 2,0,1,40); pol[6][5] = newpol("Mapa6x5", "Plocha6x5", 2,0,1,40); pol[7][5] = newpol("Mapa7x5", "Plocha7x5", 2,0,1,40); pridej_pw(68, 86, 79, "balvan7x5"); pol[0][6] = newpol("Mapa0x6", "Plocha0x6", 2,0,1,40); pridej_pw( 32, 46, 87, "studanka1-1"); pridej_pw( 62, 46, 76, "studanka1-2"); pridej_pw(120, 43, 84, "studanka2-1"); pridej_pw(153, 43, 73, "studanka2-2"); pridej_pw( 50, 128, 200, "skala0x6"); pridej_ps(&voda); pol[1][6] = newpol("Mapa1x6", "Plocha1x6", 2,0,1,40); pol[1][6]->odchfunc = opravvodu; pridej_ps(&voda); pol[2][6] = newpol("Mapa2x6", "Plocha2x6", 2,0,1,40); pol[2][6]->odchfunc = opravvodu; pridej_ps(&voda); pol[3][6] = newpol("Mapa3x6", "Plocha3x6", 2,0,1,40); pol[3][6]->prichfunc = start_jp; pridej_pw(107, 56, 30, "trava3x6"); pridej_pw(147, 128, 102, "trava7"); pridej_pw(160, 99, 73, "trava4"); pridej_pw(153, 67, 41, "trava2"); pw_xy( 34, 122); pridej_pw( 67, 57, 31, "trava6x1.2"); pw_xy(105, 134); pw_xy( 16, 96); pw_xy( 37, 66); pw_xy( 72, 130); pol[4][6] = newpol("Mapa4x6", "Plocha4x6", 2,0,1,40); pol[5][6] = newpol("Mapa5x6", "Plocha5x6", 2,0,1,40); pol[6][6] = newpol("Mapa6x6", "Plocha6x6", 2,0,1,40); pol[6][6]->prichfunc = start_jp; pridej_pw(9, 34, 10, "zaplot6x6"); pridej_pw(42, 0, 48, "palac6x6"); pridej_pw(160, 76, 104, "znacka6x6"); pridej_pw(8, 131, 112, "prplot6x6"); kq_color *vzadu; vzadu = pridejbarvu("#00C837", 0); vzadu->prichfunc = nuluj_z; vzadu->odchfunc = normal_z; pol[7][6] = newpol("Mapa7x6", "Plocha7x6", 2,0,1,40); pridej_pw(37, 12, 200, "strom7x6"); pridej_ps(&strom); pridej_ps(&voda); spojpol((kq_policko **)pol, 8,7,1,1); skala1 = newpol("skala1", "skala1", 2,0,1,40); pridej_pw(33, 49, -2, "skala1_1");
196
37 Modul kra polic 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424:
Program kraluk
pridej_pw( 0, 109, 0, "skala1_2"); skala2 = newpol("skala2", "skala2", 2,0,1,40); pridej_pw(0, 0, 0, "skala2_1"); pw_pix("plam5"); pw_pix("plam4"); pw_pix("plam3"); pw_pix("plam2"); pw_pix("plam1"); pw_anim( 96, 24, 1, 0, 0, 1, 4, 2, 4, 3, 4, 4, 4, 5, 4, pw_anim(107, 24, 1, 0, 0, 2, 4, 3, 4, 4, 4, 5, 4, 1, 4, pw_anim(115, 25, 2, 0, 0, 3, 4, 4, 4, 5, 4, 1, 4, 2, 4, pw_anim(128, 24, 1, 0, 0, 4, 4, 5, 4, 1, 4, 2, 4, 3, 4, pw_anim(140, 25, 2, 0, 0, 5, 4, 1, 4, 2, 4, 3, 4, 4, 4, pw_anim(136, 29, 6, 0, 0, 1, 4, 2, 4, 3, 4, 4, 4, 5, 4, pw_anim(124, 29, 6, 0, 0, 2, 4, 3, 4, 4, 4, 5, 4, 1, 4, pw_anim(109, 29, 6, 0, 0, 3, 4, 4, 4, 5, 4, 1, 4, 2, 4, pw_anim( 99, 28, 5, 0, 0, 4, 4, 5, 4, 1, 4, 2, 4, 3, 4, pw_anim( 88, 28, 5, 0, 0, 5, 4, 1, 4, 2, 4, 3, 4, 4, 4, pw_anim(130, 32, 9, 0, 0, 1, 4, 2, 4, 3, 4, 4, 4, 5, 4, pw_anim(117, 33, 10, 0, 0, 2, 4, 3, 4, 4, 4, 5, 4, 1, 4, pw_anim(103, 33, 10, 0, 0, 3, 4, 4, 4, 5, 4, 1, 4, 2, 4, pw_anim( 92, 31, 8, 0, 0, 4, 4, 5, 4, 1, 4, 2, 4, 3, 4, pw_anim( 82, 31, 8, 0, 0, 5, 4, 1, 4, 2, 4, 3, 4, 4, 4, pw_anim( 94, 36, 13, 0, 0, 1, 4, 2, 4, 3, 4, 4, 4, 5, 4, pw_anim( 72, 30, 7, 0, 0, 2, 4, 3, 4, 4, 4, 5, 4, 1, 4, pw_anim( 86, 34, 11, 0, 0, 3, 4, 4, 4, 5, 4, 1, 4, 2, 4, pw_anim( 76, 32, 9, 0, 0, 4, 4, 5, 4, 1, 4, 2, 4, 3, 4, skala3 = newpol("skala3", "skala3", 2,0,1,40); pridej_pw( 0, 43, 0, "skala3_1"); pridej_pw(163, 138, 105, "tyc_sk3"); pw_xy(183, 136); pw_pix("plam5"); pw_pix("plam4"); pw_pix("plam3"); pw_pix("plam2"); pw_pix("plam1"); pw_anim( 66, 27, 4, 0, 0, 1, 4, 2, 12, 3, 12, 4, 12, pw_anim( 58, 28, 5, 0, 0, 2, 8, 3, 12, 4, 12, 5, 12, pw_anim( 75, 28, 5, 0, 0, 3, 12, 4, 12, 5, 12, 1, 12, pw_anim( 42, 29, 6, 0, 0, 4, 4, 5, 12, 1, 12, 2, 12, pw_anim( 34, 31, 8, 0, 0, 5, 8, 1, 12, 2, 12, 3, 12, pw_anim( 28, 32, 9, 0, 0, 1, 12, 2, 12, 3, 12, 4, 12, pw_anim( 30, 32, 9, 0, 0, 2, 4, 3, 12, 4, 12, 5, 12, pw_anim( 83, 29, 6, 0, 0, 3, 8, 4, 12, 5, 12, 1, 12, pw_anim( 91, 30, 7, 0, 0, 4, 12, 5, 12, 1, 12, 2, 12, pw_anim( 99, 29, 6, 0, 0, 5, 4, 1, 12, 2, 12, 3, 12, pw_anim(105, 31, 8, 0, 0, 1, 8, 2, 12, 3, 12, 4, 12, pw_anim(113, 32, 9, 0, 0, 2, 12, 3, 12, 4, 12, 5, 12, pw_anim(121, 34, 11, 0, 0, 3, 4, 4, 12, 5, 12, 1, 12, pw_anim(129, 36, 13, 0, 0, 4, 8, 5, 12, 1, 12, 2, 12, pw_anim(137, 38, 15, 0, 0, 5, 12, 1, 12, 2, 12, 3, 12, pw_anim(145, 43, 20, 0, 0, 1, 4, 2, 12, 3, 12, 4, 12, pw_anim(149, 48, 25, 0, 0, 2, 8, 3, 12, 4, 12, 5, 12, pw_anim(156, 52, 29, 0, 0, 3, 12, 4, 12, 5, 12, 1, 12, pw_anim(163, 58, 35, 0, 0, 4, 4, 5, 12, 1, 12, 2, 12, pw_anim(168, 65, 42, 0, 0, 5, 8, 1, 12, 2, 12, 3, 12, pw_anim(171, 72, 49, 0, 0, 1, 12, 2, 12, 3, 12, 4, 12, pw_anim(175, 79, 56, 0, 0, 2, 4, 3, 12, 4, 12, 5, 12, pw_anim(179, 85, 62, 0, 0, 3, 8, 4, 12, 5, 12, 1, 12, pw_anim( 24, 34, 11, 0, 0, 4, 12, 5, 12, 1, 12, 2, 12, pw_anim( 32, 35, 12, 0, 0, 5, 4, 1, 12, 2, 12, 3, 12, pw_anim( 39, 33, 10, 0, 0, 1, 8, 2, 12, 3, 12, 4, 12, pw_anim( 47, 31, 8, 0, 0, 2, 12, 3, 12, 4, 12, 5, 12, pw_anim( 55, 31, 8, 0, 0, 3, 4, 4, 12, 5, 12, 1, 12, pw_anim( 63, 30, 7, 0, 0, 4, 8, 5, 12, 1, 12, 2, 12, pw_anim( 71, 31, 8, 0, 0, 5, 12, 1, 12, 2, 12, 3, 12, pw_anim( 78, 33, 10, 0, 0, 1, 4, 2, 12, 3, 12, 4, 12, pw_anim( 87, 34, 11, 0, 0, 2, 8, 3, 12, 4, 12, 5, 12,
197
-1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1);
5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
1, 8, 2, 4, -1); 4, 8, 5, 4, -1); 2, 8, 3, 4, -1); 5, 8, 1, 4, -1); 3, 8, 4, 4, -1); 1, 8, 2, 4, -1); 4, 8, 5, 4, -1); 2, 8, 3, 4, -1); 5, 8, 1, 4, -1); 3, 8, 4, 4, -1); 1, 8, 2, 4,
-1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1);
37 Modul kra polic 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492:
pw_anim( 95, pw_anim(102, pw_anim(110, pw_anim(117, pw_anim(125, pw_anim(133, pw_anim(140, pw_anim(146, pw_anim(153, pw_anim(159, pw_anim(164, pw_anim(168, pw_anim(172, pw_anim( 30, pw_anim( 41, pw_anim( 37, pw_anim( 46, pw_anim( 43, pw_anim( 51, pw_anim( 48, pw_anim( 56, pw_anim( 54, pw_anim( 62, pw_anim( 59, pw_anim( 68, pw_anim( 64, pw_anim( 73, pw_anim( 69, pw_anim( 78, pw_anim( 74, pw_anim( 82, pw_anim( 77, pw_anim( 87, pw_anim( 82, pw_anim( 90, pw_anim( 86, pw_anim( 95, pw_anim( 90, pw_anim( 99, pw_anim( 94, pw_anim(103, pw_anim( 98, pw_anim(107, pw_anim(103, pw_anim(111, pw_anim(108, pw_anim(114, pw_anim(106, pw_anim(114, pw_anim(110, pw_anim(119, pw_anim(107, pw_anim(114, pw_anim(123, pw_anim(130, pw_anim(137, pw_anim(144, pw_anim(151, pw_anim(125, pw_anim(133, pw_anim(140, pw_anim(147, pw_anim(122, pw_anim(129, pw_anim(137, pw_anim(144, pw_anim(117, pw_anim(109,
33, 34, 36, 37, 38, 41, 44, 52, 56, 61, 68, 76, 84, 38, 39, 43, 45, 48, 51, 54, 52, 56, 57, 59, 60, 62, 63, 67, 68, 71, 72, 75, 77, 80, 81, 84, 85, 89, 89, 93, 93, 98, 97, 103, 103, 110, 110, 116, 116, 122, 122, 131, 128, 128, 128, 129, 131, 130, 133, 135, 133, 135, 139, 141, 139, 139, 135, 137,
Program kraluk 10, 11, 13, 14, 15, 18, 21, 29, 33, 38, 45, 53, 61, 15, 16, 20, 22, 25, 28, 31, 29, 33, 34, 36, 37, 39, 40, 44, 45, 48, 49, 52, 54, 57, 58, 61, 62, 66, 66, 70, 70, 75, 74, 80, 80, 87, 87, 93, 93, 99, 99, 108, 105, 105, 105, 106, 108, 107, 110, 112, 110, 112, 116, 118, 116, 116, 112, 114,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5,
12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4, 8, 12, 4,
4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2,
198
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
-1); 4, 8, 5, 4, -1); 2, 8, 3, 4, -1); 5, 8, 1, 4, -1); 3, 8, 4, 4, -1); 1, 8, 2, 4, -1); 4, 8, 5, 4, -1); 2, 8, 3, 4, -1); 5, 8, 1, 4, -1); 3, 8, 4, 4, -1); 1, 8, 2, 4, -1); 4, 8, 5, 4, -1); 2, 8, 3, 4, -1); 5, 8, 1, 4, -1); 3, 8, 4, 4, -1); 1, 8, 2, 4, -1); 4, 8, 5, 4, -1); 2, 8, 3, 4, -1); 5, 8, 1, 4, -1); 3, 8, 4, 4, -1); 1, 8, 2, 4, -1); 4, 8, 5, 4, -1); 2, 8, 3, 4, -1); 5, 8,
-1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1); -1);
37 Modul kra polic 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535: 536: 537: 538: 539: 540: 541: 542: 543: 544: 545: 546: 547: 548: 549: 550: 551: 552: 553: 554: 555: 556: 557: 558: 559: 560:
Program kraluk
pw_anim(116, 140, 117, 0, 0, 1, 8, 2, 12, 3, 12, 4, 12, pw_anim(105, 139, 115, 0, 0, 2, 12, 3, 12, 4, 12, 5, 12, pw_anim(111, 145, 122, 0, 0, 3, 4, 4, 12, 5, 12, 1, 12, pw_anim(120, 144, 121, 0, 0, 4, 8, 5, 12, 1, 12, 2, 12, pw_anim(133, 143, 120, 0, 0, 5, 12, 1, 12, 2, 12, 3, 12, pw_anim(141, 145, 122, 0, 0, 1, 4, 2, 12, 3, 12, 4, 12, pw_anim(101, 144, 121, 0, 0, 2, 8, 3, 12, 4, 12, 5, 12, pw_anim( 44, 43, 20, 0, 0, 3, 12, 4, 12, 5, 12, 1, 12, skala1->vedle[VPRAVO] = skala2; skala2->vedle[VLEVO] = skala1; skala2->vedle[NAHORU] = skala3; skala3->vedle[DOLU] = skala2;
5, 1, 2, 3, 4, 5, 1, 2,
skal_zebr1 = newpol("skal_zebr1", "skal_zebr", 2, 62, 1,35); skal_zebr1->prichfunc = prichzebr; skal_zebr1->odchfunc = odchzebr; skal_zebr2 = newpol("skal_zebr2", "skal_zebr", 2, 62, 1,35); skal_zebr2->prichfunc = prichzebr; skal_zebr2->odchfunc = odchzebr; pol[0][1]->vedle[NAHORU] = skal_zebr1; skal_zebr1->vedle[DOLU] = pol[0][1]; skal_zebr1->vedle[NAHORU] = skal_zebr2; skal_zebr2->vedle[DOLU] = skal_zebr1; skal_zebr2->vedle[NAHORU] = skala3; vdrevchal = newpol("vdrevchal", "vdrevchal", 2, 0, 1, 40); vdrevchal->odchfunc = zdrchal; vdrevchal->vedle[DOLU] = pol[5][1]; pridej_pw( 67, 64, 60, "stul"); pridej_pw( 0, 3, 200, "vdrevchal_fg"); pridej_pw(109, 36, 28, "zidle"); pridej_pw( 77, 38, 31, "zidle2"); lvi = newpol("lvi", "lvi", 2, 0, 1, 34); pridejbarvu("#6B3500", 0)->prichfunc = levchyt; pridej_pw( 6, 67, 62, "lev1"); pridej_pw( 76, 66, 62, "lev2"); pridej_pw( 0, 95, 200, "lvi_fg"); peklbrana = newpol("peklbrana", "peklbrana", 2, 0, 1, 112); pridej_pw( 0, 95, 200, "lvi_fg"); peklo = newpol("peklo", "peklo", 2, 0, 1, 60); peklo->prichfunc = prich_peklo; peklo->odchfunc = opravschody; pridej_pw(33, 40, 18, "vidle"); pridej_pw(66, 0, 55, "kotel"); pridej_pw( 0, 0, 200, "peklo_fg"); schody1 = newpol("schody1", "schody1", 2, 40, 1, 30); schody1->odchfunc = opravschody; pridej_pw(43, 35, 0, "schody1"); schody2 = newpol("schody2", "schody2", 2, schody2->odchfunc = opravschody; pridej_pw(0, 38, -2, "schody2.1"); pridej_pw(0, 83, 0, "schody2.2"); pridej_pw(0, 0, 200, "schody2_fg");
0, 1, 30);
peklbrana->vedle[NAHORU] = peklo; peklo->vedle[DOLU] = peklbrana; peklo->vedle[NAHORU] = schody1; schody1->vedle[DOLU] = peklo; schody1->vedle[VPRAVO] = schody2; schody2->vedle[VLEVO] = schody1; vzamku1 = newpol("vzamku1", "vzamku1", 2, 0, 1, 90);
199
12, 12, 12, 12, 12, 12, 12, 12,
1, 4, -1); 3, 8, 4, 4, -1); 1, 8, 2, 4, -1);
-1); -1); -1); -1); -1);
37 Modul kra polic 561: 562: 563: 564: 565: 566: 567: 568: 569: 570: 571: 572: 573: 574: 575: 576: }
Program kraluk
pridej_pw(0, 0, 200, "vzamku1_fg"); vzamku2 = newpol("vzamku2", "vzamku2", 2, 0, 1, 90); pridejbarvu("#00FFFF", 0)->prichfunc = predTV; pridej_pw( 0, 0, 200, "vzamku2_fg"); pridej_pw(80, 120, 63, "televize"); pridej_pw(60, 67, 16, "kral"); pridej_ps(&kral); pridej_ps(&muz); pridej_ps(&osoba); vzamku1->vedle[DOLU] = pol[4][3]; vzamku1->odchfunc = odch_hrad; vzamku1->vedle[VLEVO] = vzamku2; vzamku2->vedle[VPRAVO] = vzamku1;
Při odchodu z políčka je třeba vynulovat znak, který je využíván pro správnou reakci na příkaz podivej se kolem. Vynulování této proměnné zajistí funkce nullujznak, která je uložena do pointeru pol_odchfunc. kra_polic.c 578: void nullujznak (kq_policko *opol, int smer, kq_policko **npol, int *x, int *y) 579: { 580: znak = 0; 581: }
Jezikož se obrázek snaží vypadat trojrozměrně, není řeka vzadu stejně široká jako vepředu. Přesto by však panáček měl po přechodu na jiné políčko být stejným způsobem u řeky nebo v řece. To zařídím funkcí opravvodu, kterou spustím vždy při odchodu z políčka s vodou, které by mohlo dělat nepříjemnosti. V případě nebezpečné řeky vždy panáčka od řeky odstrčím za bezpečnou hranici, pokud je na břehu. A pokud je ve vodě, tak ho umístím doprostřed řeky. U řeky, ve které se panáček může brodit, mám na obou políčkách tři úseky: levý břeh řeky, vnitřek řeky a pravý břeh řeky. Zde se snažím zachovat správný poměr v příslušné části. kra_polic.c 583: void opravvodu (kq_policko *opol, int smer, kq_policko **npol, int *x, int *y) 584: { 585: int ol, op, nl, np, ns; 586: 587: if(*npol == pol[0][3]){ 588: if(smer == NAHORU){ 589: ol = 15; 590: op = 33; 591: nl = 1; 592: np = 47; 593: ns = 28; 594: } 595: else if(smer == DOLU){ 596: ol = 8; 597: op = 41; 598: nl = 12; 599: np = 41; 600: ns = 24; 601: } 602: else return; 603: } 604: else if(opol == pol[0][3]){ 605: if(smer == NAHORU){ 606: ol = 17; 607: op = 36; 608: nl = 3; 609: np = 46; 610: ns = 20; 611: } 612: else if(smer == DOLU){ void nullujznak: 191, 200
void opravvodu(): 191, 193–196, 200
200
37 Modul kra polic 613: 614: 615: 616: 617: 618: 619: 620: 621: 622: 623: 624: 625: 626: 627: 628: 629: 630: 631: 632: 633: 634: 635: 636: 637: 638: 639: 640: 641: 642: 643: 644: 645: 646: 647: 648: 649: 650: 651: 652: 653: 654: 655: 656: 657: 658: 659: 660: 661: 662: 663: 664: 665: 666: 667: 668: 669: 670: 671: 672: 673: 674: 675: 676: 677: 678: 679: 680:
ol op nl np ns
= = = = =
Program kraluk
6; 42; 10; 38; 255;
} else return; } else if(*npol == pol[2][3]){ if(smer == NAHORU){ ol = 63; op = 80; nl = 38; np = 83; ns = 61; } else if(smer == DOLU){ ol = 54; op = 80; nl = 59; np = 85; ns = 72; } else return; } else if(opol == pol[2][3]){ if(smer == NAHORU){ ol = 64; op = 80; nl = 49; np = 85; ns = 68; } else if(smer == DOLU){ ol = 43; op = 78; nl = 58; np = 85; ns = 71; } else return; } else if(*npol == pol[5][3]){ if(smer == NAHORU){ ol = 58; op = 78; nl = 43; np = 94; ns = 61; } else if(smer == DOLU){ ol = 35; op = 97; nl = 44; np = 85; ns = 68; } else return; } else if(opol == pol[5][3]){ if(smer == NAHORU){ ol = 49; op = 80; nl = 30; np = 102; ns = 83; } else if(smer == DOLU){
201
37 Modul kra polic 681: 682: 683: 684: 685: 686: 687: 688: 689: 690: 691: 692: 693: 694: 695: 696: 697: 698: 699: 700: 701: 702: 703: 704: 705: 706: 707: 708: 709: 710: 711: 712: 713: 714: 715: 716: 717: 718: 719: 720: 721: 722: 723: 724: 725: 726: 727: 728: 729: 730: 731: 732: 733: 734: 735: 736: 737: 738: 739: 740: 741: 742: 743: 744: 745: 746: 747: 748:
ol op nl np ns
= = = = =
Program kraluk
48; 89; 53; 83; 67;
} else return; } else if(*npol == pol[6][3]){ if(smer == NAHORU){ ol = 36; op = 50; nl = 24; np = 62; ns = 42; } else if(smer == DOLU){ ol = 61; op = 95; nl = 64; np = 91; ns = 78; } else return; } else if(opol == pol[6][3]){ if(smer == NAHORU){ ol = 69; op = 86; nl = 56; np = 100; ns = 80; } else if(smer == DOLU){ ol = 29; op = 57; nl = 31; np = 55; ns = 42; } else return; } else if((opol == pol[3][5] && (opol == pol[3][4] && ol = 51; op = 65; nl = 29; np = 56; ns = 0; } else if((opol == pol[2][6] && (opol == pol[2][5] && ol = 71; op = 89; nl = 57; np = 91; ns = 0; } else if((opol == pol[1][0] && (opol == pol[1][6] && ol = 54; op = 69; nl = 53; np = 72; ns = 0; } else return;
smer == NAHORU) || smer == DOLU)){
smer == NAHORU) || smer == DOLU)){
smer == NAHORU) || smer == DOLU)){
202
37 Modul kra polic 749: 750: 751: 752: 753: 754: 755: 756: 757: 758: 759: 760: 761: 762: 763: 764: 765: 766: 767: 768: 769: 770: 771: 772: 773: 774: 775: 776: 777: 778: 779: 780: 781: }
Program kraluk
if(ns){ if(*x > ol && *x < op){ *x = ns; return; } if(*x <= nl || *x >= np) return; if(*x <= ol) *x = nl; else *x = np; } else{ if(smer == DOLU){ ns = ol; ol = nl; nl = ns; ns = op; op = np; np = ns; } if(*x < ol) *x = *x * nl / ol; else if(*x >= op){ ol = mapa.sirka-op; nl = mapa.sirka-np; *x -= op; *x = *x * nl / ol; *x += np; } else{ op -= ol; np -= nl; *x -= ol; *x = *x * np / op; *x += nl; } }
Stejně tak je třeba umístit panáčka na správé místo při přechodu mezi schody a peklem a mezi schody a schody. To řeší funkce opravschody. Tato funkce je volána při odchodu z pekla, takže odebere čertům kontext a vynuluje i proměnnou peklohen. V tomto modulu je i funkce prichpeklo, která je zavolána při příchodu do pekla. Tato funkce vytvoří čerty a do proměnné peklohen vytvoří widget ohně pod kotlem, který pak smažu v okamžiku, kdy bude peklo zneškodněno. kra_polic.c 831: void prich_peklo (kq_policko *npol, int smer, kq_policko *opol) 832: { 833: kq_animpost *anip; 834: 835: peklohen = vytvorwidget(62, 93, 55.2, nactikqXPM("ohen", 1), 1, 0); 836: anip = nactianip(9, 40, "cert", 4, 0, 0, 0, 1); 837: vytvorcerta(41, 14, anip); 838: vytvorcerta(22, 32, anip); 839: vytvorcerta(78, 38, anip); 840: vytvorcerta(26, 72, anip); 841: vytvorcerta(83, 73, anip); 842: certi->kontext = 1; 843: osoba->kontext = 1; 844: }
Jelikož čertů vytvořím pět, mám pro vytvoření jednoho čerta funkci vytvorcerta, které předám souřadnice a animaci postavy. kra_polic.c 816: static void vytvorcerta (int x, int y, kq_animpost *anip) 817: { 818: kq_postava *post; 819: 820: post = vytvorpost(x, y, DOLU, 3, -1, 1, 0); void opravschody(): 199 void prichpeklo() void vytvorcerta /*kra_polic*/ (): 203
widget *peklohen(): 203, 212, 244–245
203
37 Modul kra polic 821: 822: 823: 824: 825: 826: 827: 828: 829: }
Program kraluk
zmenanip(post, anip); setchytpost(post, panacek); autopost(post, auto_clever, 0, 0); post->chyt_vzdal = 5; post->chyt_func = chyt_cert; normal_z(post, NULL, NULL); post->odejde = 0; post->odraz = 1;
Když mě čert chytí, je zavolána funkce chyt_cert. Čerti se pak začnou pohybovat náhodně a čert, který panáčka chytil ho donese do kotle. Až čert dojde ke kotli, zavolá se funkce chyt_cert ještě jednou. To, zda je tato funkce zavolána poprvé nebo podruhé, poznám podle toho, zda existuje panáček. kra_polic.c 872: void chyt_cert (kq_postava *post) 873: { 874: kq_postava *pom; 875: 876: if(!panacek){ 877: post->chyt_func = NULL; 878: autopost(post, auto_random, 20, 20); 879: setchytsour(post, 0, 0); 880: return; 881: } 882: 883: znicpost(panacek); 884: panacek = ovlpost = NULL; 885: setchytsour(post, 54, 72); 886: post->chyt_vzdal = 0; 887: 888: for(pom = prvpost; pom; pom = pom->next){ 889: if(pom != post){ 890: pom->chyt_func = NULL; 891: autopost(pom, auto_random, 20, 20); 892: setchytsour(pom, 0, 0); 893: } 894: } 895: popup_info("chytil cert"); 896: }
Další políčko, ze kterého není odejití příliš obvyklé, je hrad. Když odejdu z hradu, měl bych se objevit před jeho dveřmi. To zařídí funkce odch_hrad. kra_polic.c 898: void odch_hrad (kq_policko *opol, int smer, kq_policko **npol, int *x, int *y) 899: { 900: if(smer != DOLU) return; 901: 902: *x = 27; 903: *y = 75; 904: }
Ještě je třeba upravit souřadnice při lezení po žebříku funkcí odchzebr. Tato funkce musí nastavit správné souřadnice i když se žebřík houpe, tedy když jezibaba && jezibaba->animace == jezianip. kra_polic.c 783: void odchzebr (kq_policko *opol, int smer, kq_policko **npol, int *x, int *y) 784: { 785: zebrik->slovo->kontext = 0; 786: if(opol == skal_zebr2 && smer == NAHORU){ 787: *x = 87; 788: *y = -15; 789: zmenanip(panacek, chozeni); 790: normal_z(panacek, NULL, NULL); 791: } 792: else if(opol == pol[0][1] && *npol == skal_zebr1) *x -= 66; 793: else if(opol == skal_zebr1 && *npol == pol[0][1]) *x += 66;
chyt_cert(): 204, 245
void odch_hrad(): 200, 204
204
void odchzebr(): 192, 199, 204
38 Modul kra input
Program kraluk
794: if(jezibaba && jezibaba->animace == jezianip){ 795: if(*npol == skal_zebr1) *x -= 3; 796: else if(*npol == skal_zebr2) *x = 22; 797: else if(*npol == pol[0][1]) *x = 88; 798: } 799: }
Funkce prichzebr je zavolána při příchodu k žebříku. Tato funkce nastaví žebříku správný kontext a navíc v případě, že je na políčku skal_zebr1, zobrazí správný žebřík (houpající se nebo rovný). kra_polic.c 801: void prichzebr (kq_policko *opol, int smer, kq_policko *npol) 802: { 803: if(!zebrik->stav) return; 804: 805: zebrik->slovo->kontext = 1; 806: if(npol == pol[0][1]){ 807: vytvorsubmap( 76, 46, 5, "spodzebr", 1, 0); 808: vytvorwidget(164, 0, 49, nactikqXPM("spodzebr", 1), 1, 0); 809: } 810: else if(npol == skal_zebr1){ 811: if(jezibaba && jezibaba->animace == jezianip) houpejzebr(); 812: else vytvorwidget(94, 0, 0, nactikqXPM("zebrik", 1), 1, 0); 813: } 814: }
38 Modul kra input Funkcí vetyslova vytvořím slova používaná v programu (datový typ kq_word) a nastavím také větám funkce. Při startu programu je nejprve volána tato funkce a pak teprve funkce vytvorpredmety, takže jsou v souboru se slovy nejprve normální slova a potom teprve slova předmětů. kra_input.c 3: void vetyslova () 4: { 5: dvere = add_word(0); 6: strom = add_word(0); 7: muz = add_word(0); 8: zemisto = add_word(1); 9: voda = add_word(0); 10: tresne = add_word(0); 11: divka = add_word(0); 12: smolicek = add_word(0); 13: jelen = add_word(0); 14: krkavci = add_word(0); 15: kral = add_word(0); 16: bohdanka = add_word(0); 17: maruska = add_word(0); 18: lada = add_word(0); 19: krasomila = add_word(0); 20: osoba = add_word(0); 21: lotrando = add_word(0); 22: bobes = add_word(0); 23: jezislovo = add_word(0); 24: jezinky = add_word(0); 25: certi = add_word(0); 26: lev = add_word(0); 27: 28: add_sent(&konec); 29: add_sent(&ukazjaz); 30: add_sent(&daruj); 31: add_sent(&seber); 32: add_sent(&otevri); 33: add_sent(&zavri); 34: /**/add_sent(&prozkoumej); 35: add_sent(&vylez); void prichzebr(): 192, 199, 205
void vetyslova(): 190, 205
205
38 Modul kra input 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: }
Program kraluk
add_sent(&slez); add_sent(&oblec); add_sent(&svlec); add_sent(&spustzebr); add_sent(&nalej); add_sent(&vylej); add_sent(&mluv); add_sent(&privaz); add_sent(&posun); add_sent(&okoli); add_sent(&zapalsvicku); add_sent(&domu); add_sent(&snez);
Slovo zemisto je slovo, které nemá žádnou důležitou úlohu podobně jako funkce prozkoumej. Původně jsem zamýšlel, že bude funkce prozkoumej dávat nápovědu, přičemž jedna z nejčastějších věcí, co by byla prozkoumána, je právě zem. kra_input.c 673: void prozkoumej (int pocet, kq_word **slova) 674: { 675: // printf("prozkoumej jeste neni implementovano\n"); 676: popup_info("neni duvod"); 677: }
Pak jsem ale shledal takovouto variantu příliš pracnou, protože prozkoumávat se dá ledaccos a na některych políčkách se dá těžko uvažovat o nějaké zemi. Hlavní napovídací funkcí místo toho je funkce okoli, která je zavolána při povelu rozhlédni se, prozkoumej okolí, . . . Tato funkce vyskočí s oknem s textem podle labelíku stejného, jako je název pozadí scény. V případě, že se zde nalézá předmět, tak, když tento předmět má stav false, připojí k názvu pixmapy ještě ".0". Když je stav předmětu true, tak k názvu připojí ".1". Další proměnnou, která může to, co panáček vidí, na scéně ovlivňovat, je znak. Pokud znak != 0, tak se k názvu scény připojí ještě podtržítko a tento znak. kra_input.c 602: void okoli (int pocet, kq_word **slova) 603: { 604: char *str1, *str2, pomstr[3]; 605: 606: if(!panacek){ 607: popup_info("nemuzes nic"); 608: return; 609: } 610: 611: if(aktupol->predmety){ 612: if(aktupol->predmety->stav) str1 = joinstrings(aktupol->jmpixmap, ".1", NULL); 613: else str1 = joinstrings(aktupol->jmpixmap, ".0", NULL); 614: } 615: else str1 = aktupol->jmpixmap; 616: 617: if(znak){ 618: pomstr[0] = ’_’; 619: pomstr[1] = znak; 620: pomstr[2] = 0; 621: str2 = joinstrings(str1, pomstr, NULL); 622: } 623: else str2 = str1; 624: 625: popup_info(str2); 626: 627: if(str2 != str1) free(str2); 628: if(str1 != aktupol->jmpixmap) free(str1); 629: }
Slovo dvere je použito pro otvírání dveří. Druhé slovo, které se dá otevřít, je slovo předmětu kq_word *zemisto(): 205 void prozkoumej(): 205–206 void okoli(): 126, 206 char znak: 200, 206, 208–210, 212, 215–216, 221, 224–229, 235, 237–238, 244–245 kq_word *dvere: 192–193, 195, 205, 207–208, 232
206
38 Modul kra input
Program kraluk
kokos. Funkce otevri je spuštěna v případě příkazu o otevření kokosu nebo dveří. kra_input.c 120: void otevri (int pocet, kq_word **slova) 121: { 122: if(!panacek){ 123: popup_info("nemuzes nic"); 124: return; 125: } 126: 127: if(slova[0] == kokos->slovo){ 128: if(!kokos->inv){ 129: popup_info("nemas kokos"); 130: return; 131: } 132: if(!kokos->stav){ 133: popup_info("kok uz otv"); 134: return; 135: } 136: zmenprnazev(kokos, "kokpul"); 137: popup_info("otevrel kokos"); 138: predmetinv(mkozisek); 139: } 140: 141: if(pocet == 1 && slova[0] == dvere){ 142: if(!dvere_post){ 143: popup_info("neni duvod"); 144: return; 145: } 146: if(aktupixel() != dosahpredmet){ 147: popup_info("_too far"); 148: return; 149: } 150: if(dvere_post->animstav >= 8){ 151: popup_info("opened door"); 152: } 153: else{ 154: panacek->smer = NAHORU; 155: panacek->xx = panacek->yy = 0; 156: zmenapost(panacek); 157: } 158: 159: if(dvere_tim) dvere_tim->parametr = pinint(1); 160: else dvere_tim = vytvortimer(&men_dvere, pinint(1), 2, 0, 0, 1, 0); 161: } 162: }
Když mají být otevřeny dveře, založí funkce otevri timer, který postupně posouvá dveře tak, že opakovaně volá funkci men_dvere. Tento timer, je uložen v proměnné dvere_tim. Funkce men_dvere posune stav animace postavy dvere_post, která se vyskytuje na políčku pol[4][3]. Funkce men_dvere je volána při otvírání i při zavírání dveří. To, jak má stav animace dveří posunout, je udáno v parametru jak. V případě, že stav animace je 0, jsou dveře zavřené a když je 8, tak jsou otevřené. V případě, že jsou zcela otevřené, je dveřím přiřazena submapa, která umožní průchod do hradu. kra_input.c 101: void men_dvere (int jak) 102: { 103: if(dvere_post->animstav + jak > 8 || dvere_post->animstav + jak < 0){ 104: znictimer(dvere_tim); 105: dvere_tim = NULL; 106: return; 107: } 108: 109: if(dvere_post->submap){ 110: znicsubmap(dvere_post->submap); 111: dvere_post->submap = NULL; void otevri: 51, 89, 101, 104, 205, 207 kq_timer *dvere_tim: 207–208, 243–244 men_dvere(): 207–208, 244 kq_postava *dvere_post: 194, 207–208, 244
207
void
38 Modul kra input 112: 113: 114: 115: 116: 117: 118: }
Program kraluk
} dvere_post->animstav += jak; if(dvere_post->animstav == 8) dvere_post->submap = vytvorsubmap(19, 74, 15, "h_dvere", 1, 0); zmenapost(dvere_post);
Dveře je možné narozdíl od kokosu opět zavřít funkcí zavri. kra_input.c 164: void zavri (int pocet, kq_word **slova) 165: { 166: if(!panacek){ 167: popup_info("nemuzes nic"); 168: return; 169: } 170: 171: if(pocet != 1 || slova[0] != dvere || !dvere_post){ 172: popup_info("neni duvod"); 173: return; 174: } 175: 176: if(aktupixel() != dosahpredmet){ 177: popup_info("_too far"); 178: return; 179: } 180: if(dvere_post->animstav <= 0){ 181: popup_info("closed door"); 182: } 183: else{ 184: panacek->smer = NAHORU; 185: panacek->xx = panacek->yy = 0; 186: zmenapost(panacek); 187: } 188: 189: if(dvere_tim) dvere_tim->parametr = pinint(-1); 190: else dvere_tim = vytvortimer(&men_dvere, pinint(-1), 2, 0, 0, 1, 0); 191: }
Slovo strom je slovem, na které se dá vylézt funkcí vylez. Kromě stromu je možné vylézt na slovo předmětu zebrik. Vylezením na strom schovám panáčka a odschovám ho až v okamžiku, kdy panáček opět za stromu sleze. To, zda je panáček právě na stromě, udává proměnná nastrome. Navíc je po dobu, co je panáček na stromě, nastaven znak na ’s’. Strom na políčku pol[2][4] je specifický tím, že se na něm může nalézat brnění (předmět brneni). To, zda je brnění na stromě nebo už ho panáček sundal, udává proměnná brnnastr (true = je na stromě). Když je panáček na stromě, na kterém se nachází brnění, je znak nastaven na ’b’. Když panáček leze po žebříku, je mu změněna animace a také Z-ková souřadnice, aby animace správně fungovala. Když na žebřík vyleze zespod, je jen posunut na žebřík, když na něj leze ze skály, je změněno políčko. kra_input.c 193: void vylez (int pocet, kq_word **slova) 194: { 195: if(!panacek){ 196: popup_info("nemuzes nic"); 197: return; 198: } 199: if(strom->kontext<=0 && zebrik->slovo->kontext<=0){ 200: popup_info("vylez kam?"); 201: return; 202: } 203: if(strom->kontext<=0 && !zebrik->stav){ 204: if(pocet && slova[0]) popup_info("je srolovany"); 205: else popup_info("vylez kam?"); 206: return; void zavri(): 205, 208 kq_word *strom: 192–196, 205, 208–209 char nastrome: 209–210, 216, 244
208
void vylez(): 205, 208
38 Modul kra input 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: }
Program kraluk
} if(panacek->animace == lezeni){ popup_info("zebr sipky"); return; } if(!najdibarvu (dosahpredmet, panacek->x, panacek->y)){ popup_info("_too far"); return; } if(panacek->animace == brnanip){ if(strom->kontext>0) popup_info("ne na str v brn"); else popup_info("ne na zebr v brn"); return; } if(strom->kontext>0){ if(nastrome) popup_info("byl strom"); else popup_info("je strom"); hidepost(panacek); nastrome = 1; if(aktupol == pol[2][4] && brnnastr){ brneni->slovo->kontext++; znak = ’b’; } else znak = ’s’; } else{ if(aktupol == skala3){ kql_square(panacek, skal_zebr2, 23, 0,0,0,0); if(pol_prichfunc) pol_prichfunc(skala3, DOLU, skal_zebr2); } else{ panacek->x = 89; panacek->y = 15; if(jezibaba) jezicekej(); } zmenanip(panacek, lezeni); post_z(panacek, 0, 0.1, 49.2); anip_step(panacek); panacek->xx = panacek->yy = 0; }
Ze stromu se dá opět slézt funkcí slez. kra_input.c 251: void slez (int pocet, kq_word **slova) 252: { 253: if(!panacek){ 254: popup_info("nemuzes nic"); 255: return; 256: } 257: if(panacek->animace == lezeni){ 258: popup_info("zebr sipky"); 259: return; 260: } 261: if(!nastrome){ 262: if(pocet && slova[0] == strom) popup_info("nebyl strom"); 263: else if(pocet && slova[0] == zebrik->slovo) popup_info("nebyl zebr"); 264: else popup_info("slez odkud?"); 265: return; 266: } 267: popup_info("neni strom"); 268: panacek->xx = panacek->yy = 0; 269: unhidepost(panacek); 270: nastrome = 0; void slez(): 206, 209
209
38 Modul kra input
Program kraluk
271: znak = 0; 272: 273: if(brneni && brnnastr && aktupol == pol[2][4]) brneni->slovo->kontext--; 274: }
Další jednoduchá akce se slovy je jezení, což má na starost funkce snez. Sníst se dají třešně (slovo tresne) nebo slovo předmětu pernicek. Jezení třešní nemá žádný efekt, když panáček sní perník, tak ho ztratí z inventáře. kra_input.c 582: void snez (int pocet, kq_word **slova) 583: { 584: if(slova[0] == tresne){ 585: if(aktupol != pol[2][0] || aktupixel() != dosahpredmet){ 586: popup_info("_too far"); 587: return; 588: } 589: popup_info("ji tresne"); 590: } 591: else if(slova[0] == pernicek->slovo){ 592: if(!pernicek->inv){ 593: popup_info("nemas pernik"); 594: return; 595: } 596: predmetnull(pernicek); 597: popup_info("snedl pernik"); 598: } 599: else popup_info("neni duvod"); 600: }
Funkce oblec obleče panáčka do brnění. Tato funkce je zavolána, i když hráč chce, aby se panáček oblékl do myšího kožíšku, to však je zamítnuto. Panáček se nesmí vyskytovat s brněním ve vodě, takže pokusem o jeho oblečení ho ztratí. Rovněž není možné, aby měl panáček brnění na sobě v okamžiku, kdy po něčem leze. kra_input.c 276: void oblec (int pocet, kq_word **slova) 277: { 278: if(!panacek){ 279: popup_info("nemuzes nic"); 280: return; 281: } 282: if(slova[0] == mkozisek->slovo){ 283: popup_info("oblec kozisek"); 284: return; 285: } 286: if(panacek->animace == brnanip){ 287: popup_info("jsi v brn"); 288: return; 289: } 290: if(!brneni->inv){ 291: popup_info("nemas brn"); 292: return; 293: } 294: if(nastrome){ 295: popup_info("ne brn na str"); 296: return; 297: } 298: if(panacek->animace == lezeni){ 299: popup_info("ne brn na zebr"); 300: return; 301: } 302: if(panacek->animace != chozeni){ 303: predmetnull(brneni); 304: popup_info("oblec uhas"); 305: return; 306: } void snez(): 206, 210
kq_word tresne: 192, 205, 210
210
void oblec(): 206, 210
38 Modul kra input
Program kraluk
307: 308: popup_info("v brneni"); 309: panacek->tim->cas = 10; 310: zmenanip(panacek, brnanip); 311: }
Funkce svlec opět brnění z panáčka sundá. Této funkci je rovněž možné předat jako parametr slovo předmětu kozisek. kra_input.c 313: void svlec (int pocet, kq_word **slova) 314: { 315: if(slova[0] == mkozisek->slovo){ 316: popup_info("svlec kozisek"); 317: return; 318: } 319: if(!panacek || panacek->animace != brnanip){ 320: popup_info("nejsi v brn"); 321: return; 322: } 323: if(aktupixel() == ohen){ 324: popup_info("svlec shor"); 325: znicpost(panacek); 326: ovlpost = panacek = NULL; 327: return; 328: } 329: 330: popup_info("mimo brneni"); 331: panacek->tim->cas = 3; 332: zmenanip(panacek, chozeni); 333: }
Funkce nalej naleje vodu do kýblu. To je možné jen v případě, když panáček stojí ve vodě nebo u studánky a má kýbl. Když si panáček nabere vodu z levé studánky, je předmětu kybl přiřazen název kybl+voda) a voda v kýblu je světlejší než když si panáček nabere vodu jinde. Parametr slova[0] může být NULL nebo kybl a parametr slova[1] může být NULL nebo voda. Voda má kontext jen na políčkách, na kterých je řeka. Také má voda kontext, když je v kýblu. kra_input.c 356: void nalej (int pocet, kq_word **slova) 357: { 358: if(pocet != 2) warning("nalej ma misto dvou parametru %d", pocet); 359: 360: if(!panacek){ 361: popup_info("nemuzes nic"); 362: return; 363: } 364: if(kybl->stav){ 365: popup_info("uz mas vodu"); 366: return; 367: } 368: else if(panacek->animace != topeni && panacek->animace != vevode3 && 369: panacek->animace != vevode2 && panacek->animace != vevode1 && 370: (aktupol != pol[0][6] || 371: aktupixel() != dosahpredmet)){ 372: popup_info("_too far"); 373: return; 374: } 375: else if(!kybl->inv){ 376: if(slova[0]) popup_info("nemas kybl"); 377: else popup_info("nalej kam?"); 378: return; 379: } 380: 381: popup_info("nalil"); 382: if(aktupol == pol[0][6] && panacek->x < 52) zmenprnazev(kybl, "kybl+voda");
void svlec(): 206, 211
void nalej(): 206, 211
kq_word *voda: 192–196, 205, 211–212, 220
211
38 Modul kra input
Program kraluk
383: else zmenprnazev(kybl, "kybl+vod"); 384: voda->kontext++; 385: }
Funkce vylej vyleje vodu z kýblu. Zvláštní efekt to má pouze v případě, že hráč stojí v pekle a má tu správnou vodu. V takovém případě zmizí čerti a peklohen. kra_input.c 387: void vylej (int pocet, kq_word **slova) 388: { 389: if(pocet != 2) warning("vylej ma misto dvou parametru %d", pocet); 390: 391: if(!panacek){ 392: popup_info("nemuzes nic"); 393: return; 394: } 395: if(!kybl->stav && slova[1]){ 396: popup_info("nemas vodu"); 397: return; 398: } 399: else if(!kybl->inv && slova[0]){ 400: popup_info("nemas kybl"); 401: return; 402: } 403: else if(!kybl->stav){ 404: popup_info("co vylit?"); 405: return; 406: } 407: 408: if(!strcmp(kybl->nazev, "kybl+voda") && aktupol == peklo){ 409: znicwidget(peklohen); 410: peklohen = NULL; 411: while(prvpost != panacek) znicpost(prvpost); 412: popup_info("zneskodneno peklo"); 413: certi->kontext = 0; 414: osoba->kontext = 0; 415: znak = ’x’; 416: } 417: else if(kybl->stav && aktupol == peklo) popup_info("spatna voda"); 418: else popup_info("vylil"); 419: zmenprnazev(kybl, "kybl"); 420: voda->kontext--; 421: }
Další hintovací funkce mluv zařizuje komunikaci s postavami. Jelikož je většinou na scéně jen jedna postava, stačí se podívat, které postavy zrovna mají kontext. Díky tomu mohu napsat mluv s osobou a program to pochopí. Jediná situace, kdy je na sccéně více osob, je ta, kde jsou jezinky i smolíček. Konkrétní osoby jsou: smolicek, jelen, kral, bohdanka, maruska, lada, krasomila, lotrando, bobes, krkavci, jezislovo (jezibaba), jezinky, certi, lev. Slovo osoba sdružuje všechny konkrétní osoby kromě zvířat. Slovo muz shrnuje konkrétní osoby lotrando, kral a bobes. Slovo předmětu princezna shrnuje osoby lada, maruska, krasomila a kromě toho vystupuje samostatně. Slovo divka shrnuje všechny princezny a navíc Bohdanku.
void vylej(): 206, 212 void mluv(): 206, 213 kq_word *smolicek: 192, 205, 213, 215, 227–228 kq_word *jelen: 193, 205, 213, 215, 229 kq_word *kral: 9–10, 187, 190, 200, 205, 212–214 kq_word *bohdanka: 205, 213, 237, 242 kq_word *maruska: 205, 212–213, 226–227, 242 kq_word *lada: 10, 19, 91, 114, 205, 212–213, 226–227, 242 kq_word *krasomila: 205, 212–213, 226–227 kq_word *lotrando: 205, 212–214, 226–227 kq_word *bobes: 195, 205, 212–213 kq_word *krkavci: 193, 205, 213–214, 235–236 kq_word *jezislovo: 205, 213, 230–231, 234 kq_word *jezinky: 192, 205, 213 kq_word *certi: 203, 205, 212–213 kq_word *lev: 9–10, 44, 47, 200, 205, 213, 224, 238 kq_word *osoba: 195, 200, 203, 205, 212–213, 216, 226–231, 234, 237–238 kq_word muz: 47, 195, 200, 205, 226–227 kq_word *divka: 205, 213, 216, 226–227, 237–238
212
38 Modul kra input
Program kraluk kra_input.c
515: void mluv (int pocet, kq_word **slova) 516: { 517: if(pocet < 1){ 518: warning("funkce mluv ma malo parametru (pocet < 1)"); 519: return; 520: } 521: 522: if(!panacek){ 523: popup_info("nemuzes nic"); 524: return; 525: } 526: 527: if(slova[0] == sluchatko->slovo){ 528: if(!sluchatko->inv) popup_info("nemas sluchatko"); 529: popup_info("sluchatko nemluvi"); 530: return; 531: } 532: if(jinapost){ 533: if(smpixel(jinapost->submap, panacek->x, panacek->y) != dosahpredmet){ 534: popup_info("_too far"); 535: return; 536: } 537: 538: if(jelen->kontext > 0) popup_info("jelen nemluvi"); 539: else if(krasomila->kontext > 0) popup_info("krasomila nemluvi"); 540: else if(lotrando->kontext > 0) popup_info("lotrando nemluvi"); 541: else if(!(zkusmluvit(maruska) || 542: zkusmluvit(lada) || zkusmluvit(krasomila))) 543: warning("neznama osoba"); 544: } 545: else{ 546: if(certi->kontext > 0) popup_info("certi nemluvi"); 547: else if(krkavci->kontext > 0) popup_info("krkavci nemluvi"); 548: else if(lev->kontext > 0 && (slova[0] == lev || divka->kontext <= 0)) 549: popup_info("lvi nemluvi"); 550: else if(aktupol == lvi) popup_info("spici nemluvi"); 551: else if(jezislovo->kontext) popup_info("jezibaba nemluvi"); 552: else{ 553: if(aktupixel() != dosahpredmet && 554: (kral->kontext <= 0 || aktupixel() == zem || panacek->y > 28)){ 555: if(jezinky->kontext > 0 && slova[0] != smolicek){ 556: popup_info("jezinky nemluvi"); 557: return; 558: } 559: popup_info("_too far"); 560: return; 561: } 562: 563: if(smolicek->kontext > 0){ 564: if(slova[0] == jezinky){ 565: popup_info("jezinky nemluvi"); 566: return; 567: } 568: if(smoldal){ 569: popupoutput("uz smol dal", NULL, 0.7, 0.3, 0.5, 0.1); 570: return; 571: } 572: popupoutput("smol dava", NULL, 0.7, 0.3, 0.5, 0.1); 573: smoldal = 1; 574: predmetinv(odsmolicka); 575: } 576: else if(!(zkusmluvit(bohdanka) || zkusmluvit(kral) || zkusmluvit(bobes))) 577: warning("neznama osoba"); 578: } 579: } 580: }
213
38 Modul kra input
Program kraluk
Dialogy s některými postavami mají tři políčka: vlevo, vpravo, vlevo. Funkce zkusmluvit dostane slovo. Pokud toto slovo má kladný kontext, zobrazí takový tříokenný dialog a vrátí true. Jinak vrátí false. kra_input.c 506: static char zkusmluvit (kq_word *skym) 507: { 508: if(skym->kontext <= 0) return 0; 509: popupoutput("talk", skym, 0.5, 0.7, 0.1, 0.5); 510: popupoutput("talk2", skym, 0.5, 0.7, 0.9, 0.5); 511: popupoutput("talk3", skym, 0.5, 0.7, 0.1, 0.5); 512: return 1; 513: }
Funkce daruj řeší situace, kdy se panáček snaží někomu něco dát. Pokud dává nesprávný předmět, je zobrazena hláška, která má slovo, které chce hráč darovat jako parametr. kra_input.c 423: void daruj (int pocet, kq_word **slova) 424: { 425: if(!panacek){ 426: popup_info("nemuzes nic"); 427: return; 428: } 429: 430: if(kral->kontext > 0){ 431: if(slova[0] == sluchatko->slovo){ 432: if(aktupixel() != dosahpredmet && (aktupixel() == zem || panacek->y > 28)){ 433: popup_info("_too far"); 434: return; 435: } 436: popup_info("vyhral jsi"); 437: kql_restart(); 438: } 439: else popupwarning("kral bez zajmu", slova[0]->nazev); 440: return; 441: } 442: if(krkavci->kontext > 0){ 443: if(slova[0] == pernicek->slovo){ 444: predmetnull(pernicek); 445: promenujkrk(); 446: } 447: else popupwarning("krkavci bez zajmu", slova[0]->nazev); 448: return; 449: } 450: if(!jinapost || jinapost->hide){ 451: popupwarning("daruj komu?", slova[0]->nazev); 452: return; 453: } 454: else if(smpixel(jinapost->submap, panacek->x, panacek->y) != dosahpredmet){ 455: popup_info("_too far"); 456: return; 457: } 458: else if(lotrando->kontext){ 459: predmetnull(slova[0]->informace.u.p); 460: popupwarning("uloupil", slova[0]->nazev); 461: znicpost(jinapost); 462: } 463: else if(aktupol == pol[7][0] && slova[0] == mkozisek->slovo){ 464: predmetnull(mkozisek); 465: predmetinv(hvezdicka); 466: popup_info("dostal hvezdu"); 467: makozisek = 1; 468: zmenanip(jinapost, nactianip(9, 40, "mkozisek", 4, 0, 0, 0, 1)); 469: autopost(jinapost, NULL, 0, 0); 470: } 471: else if(aktupol == pol[2][2] && slova[0] == odsmolicka->slovo){ 472: predmetnull(odsmolicka); char zkusmluvit /*kra_input*/ (): 213–214
daruj: 205, 214
214
38 Modul kra input 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: }
Program kraluk
popup_info("bezel jelen"); znak = ’x’; znicpost(jinapost); predmetpol(kaminek, aktupol, 16, 57, 0, 1, 52, 5); jelen->kontext--; smolicek->kontext--; } else if(aktupol == pol[3][6] && slova[0] == slanka->slovo){ predmetnull(slanka); dostalkyt = 1; popup_info("dostal kytku"); autopost(jinapost, NULL, 0, 0); predmetinv(kytka); } else if(aktupol == pol[6][6] && slova[0] == kytka->slovo){ predmetnull(kytka); dostalsvic = 1; popup_info("dostal svicku"); autopost(jinapost, auto_clever, 0, 0); jinapost->chyt_vzdal = 0; setchytsour(jinapost, 35, 56); predmetinv(svicka); } else{ if(aktupol == pol[7][0] || aktupol == pol[3][6] || aktupol == pol[6][6]) popupwarning("princezna bez zajmu", slova[0]->nazev); if(aktupol == pol[2][2]) popupwarning("jelen bez zajmu", slova[0]->nazev); }
Funkce spustzebr spustí žebřík, aby po něm bylo možné lézt. kra_input.c 335: void spustzebr (int pocet, kq_word **slova) 336: { 337: if(!panacek){ 338: popup_info("nemuzes nic"); 339: return; 340: } 341: if(zebrik->stav){ 342: popup_info("je spusteny"); 343: return; 344: } 345: if(!najdibarvu (dosahpredmet, panacek->x, panacek->y)){ 346: popup_info("_too far"); 347: return; 348: } 349: 350: zmenprnazev(zebrik, "odrolzebr"); 351: predmetpol(zebrik, skala3, 352: 162, 102, 0.2, 353: 78, 101, 5); 354: }
Funkce seber sebere ze země předmět nebo brnění ze stromu. Pro sebrání předmětu je využita funkce seberslovo, která si bere souřadnice z ovlpost. Proto na chvíli nastavím ovlpost jako panacek. kra_input.c 62: void seber (int pocet, kq_word **slova) 63: { 64: int i; 65: kq_postava *oovl; 66: 67: if(!panacek){ 68: popup_info("nemuzes nic"); void spustzebr(): 206, 215
void seber(): 25, 205, 215
215
38 Modul kra input 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: }
Program kraluk
return; } oovl = ovlpost; ovlpost = panacek; if(pocet != 1) return; if(slova[0] == osoba || slova[0] == divka) slova[0] = princezna->slovo; if(brneni && slova[0] == brneni->slovo){ if(brneni->inv) uzmaspredmet(brneni); else{ predmetinv(brneni); sebralspredmet(brneni); znak = ’s’; } brnnastr = 0; ovlpost = oovl; return; } else if((i = seberslovo(slova[0])) > 0){ if(slova[0] == pernicek->slovo) startjezi(); if(aktupol == vdrevchal){ krkstav = 0; kql_square(panacek, pol[5][1], 69, 91, 0, 0, 0); znak = ’z’; panacek->smer = DOLU; } } else if(i < 0) popup_info("neni duvod"); ovlpost = oovl;
Funkce zapalsvicku učiní, že svíčka, kterou má hráč v inventáři, začne hořet. kra_input.c 631: void zapalsvicku (int pocet, kq_word **slova) 632: { 633: if(!panacek){ 634: popup_info("nemuzes nic"); 635: return; 636: } 637: if(!svicka->inv || svicka->stav){ 638: popup_info("neni duvod"); 639: return; 640: } 641: popup_info("zapaluje"); 642: zmenprnazev(svicka, "zapsvic"); 643: }
Funkce domu dostane panáčka ke králi v případě, že má kouzelné sluchátko. kra_input.c 645: void domu (int pocet, kq_word **slova) 646: { 647: if(!panacek){ 648: popup_info("nemuzes nic"); 649: return; 650: } 651: if(!sluchatko->inv){ 652: popup_info("jak domu?"); 653: return; 654: } 655: unhidepost(panacek); 656: nastrome = 0; 657: znak = 0; 658: if(panacek->animace == lezeni) zmenanip(panacek, chozeni); 659: normal_z(panacek, NULL, NULL); 660: if(telepost){ void zapalsvicku(): 206, 216
void domu(): 206, 216
216
39 Modul kra barvy 661: 662: 663: 664: 665: 666: 667: 668: 669: 670: 671: }
Program kraluk
znicpost(telepost); telepost = NULL; } if(teletim){ znictimer(teletim); teletim = NULL; } ovlpost = panacek; kql_square(panacek, vzamku2, 58, 20, 0, 0, 0); panacek->barvy = 1;
Funkce ukazjaz zobrazí seznam jazyků. kra_input.c 56: void ukazjaz (int pocet, kq_word **slova) 57: { 58: if(pocet == 0) zobrazjazyky(); 59: else warning("ukazjaz: spatny pocet slov"); 60: }
Funkce konec ukončí program. kra_input.c 51: void konec (int pocet, kq_word **slova) 52: { 53: kql_exit(); 54: }
39 Modul kra barvy Tento modul obsahuje funkce, které se spustí při změně barvy. Dále je zde funkce nactigbarvy, která nastaví barvy, které jsou globální, tedy nepřísluší pouze nějakému políčku. kra_barvy.c 3: void nactigbarvy () 4: { 5: kq_color *voda1, *voda2, *voda3; 6: zed = pridejbarvu("#000000", 1); 7: zem = pridejbarvu("#00FF00", 0); 8: voda1 = pridejbarvu("#AB9AFF", 0); 9: voda2 = pridejbarvu("#846CFF", 0); 10: voda3 = pridejbarvu("#6243FF", 0); 11: breh = pridejbarvu("#AC4900", 0); 12: nebvoda1 = pridejbarvu("#0000FF", 0); 13: nebvoda2 = pridejbarvu("#0000BF", 0); 14: nebvoda3 = pridejbarvu("#000080", 0); 15: nebvoda4 = pridejbarvu("#000040", 0); 16: ohen = pridejbarvu("#FF9600", 0); 17: ohen->prichfunc = shor; 18: pridejbarvu("None", 0)->z = -1000; 19: dosahpredmet = pridejbarvu("#00BB00", 0); 20: dosahpredmet->z = -10; 21: pridejbarvu("#6B1E77", 0)->prichfunc = barvapolic; 22: 23: skalopad1 = pridejbarvu("#CCCC00", 0); 24: skalopad2 = pridejbarvu("#E6E600", 0); 25: skalopad3 = pridejbarvu("#FFFF00", 0); 26: skalopad1->prichfunc = skalopad2->prichfunc = skalopad3->prichfunc = skalopada; 27: 28: breh->prichfunc = paddovody; 29: 30: voda1->prichfunc = brodi1; 31: voda2->prichfunc = brodi2; 32: voda3->prichfunc = brodi3; 33: nebvoda1->prichfunc = topise; 34: nebvoda2->prichfunc = topise; void ukazjaz(): 205, 217
void konec(): 29, 90, 129, 164, 205, 217
217
void nactigbarvy(): 190, 217
39 Modul kra barvy 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: }
Program kraluk
nebvoda3->prichfunc = topise; nebvoda4->prichfunc = topise; voda1->odchfunc = sucho; voda2->odchfunc = sucho; voda3->odchfunc = sucho; nebvoda1->odchfunc = sucho; nebvoda2->odchfunc = sucho; nebvoda3->odchfunc = sucho; nebvoda4->odchfunc = sucho;
Barva zem je nejběžnější barva, na které panáček stojí bez jakýchkoli zvláštních účinků. Barva zed je barva, na kterou panáček nemůže vstoupit, ale nic se při pokusu o to nestane. Funkce aktupixel vrátí barvu z mapy mapa v místě, kde právě stojí panacek. kra_barvy.c 47: kq_color *aktupixel () 48: { 49: if(!panacek) return NULL; 50: return mappixel(mapa, panacek->x, panacek->y); 51: }
Funkce normal_z přiřadí postavě Z-kovou souřadnici, která se počítá jako Y-ová souřadnice plus 0.5. Dostane dva zbytečné parametry barev, aby mohla být použita jako funkce příchodu nebo odchodu z barvy na políčku pol[6][6]. kra_barvy.c 58: void normal_z (kq_postava *post, kq_color *b1, kq_color *b2) 59: { 60: post_z(post, 0,1, 0.5); 61: }
Funkce nuluj_z nastaví postavě nulovou souřadnici. Tato funkce také nachází uplatnění na pol[6][6]. kra_barvy.c 53: void nuluj_z (kq_postava *post, kq_color *b1, kq_color *b2) 54: { 55: post_z(post, 0,0,0); 56: }
Při vstupu do vody, ve které se panáček brodí (nebo plave) je zavolána jedna z funkcí brodi1, brodi2, brodi3, plave. kra_barvy.c 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96:
void brodi1 (kq_postava *post, kq_color *nova, kq_color *stara) { dovody(vevode1); } void brodi2 (kq_postava *post, kq_color *nova, kq_color *stara) { dovody(vevode2); } void brodi3 (kq_postava *post, kq_color *nova, kq_color *stara) { dovody(vevode3); } void plave (kq_postava *post, kq_color *nova, kq_color *stara) { dovody(plavani); }
Tyto funkce zavolají funkci dovody, která nastaví panáčkovi příslušnou animaci. V případě, že má na sobě panáček brnění, o něj přijde. kra_barvy.c 76: static void dovody (kq_animpost *anip) 77: { 78: if(panacek->animace == brnanip){ 79: panacek->tim->cas = 3; 80: popup_info("vstup uhas"); 81: predmetnull(brneni); kq_color *zem: 213–214, 217, 220 kq_color *zed: 53–54, 63, 69, 77, 174, 217, 222, 239–240 void normal_z(): 190, 196, 204, 216, 218–221, 223–224, 226, 228–231, 235, 238 void nuluj_z(): 196, 218–219 void brodi1(): 217–218, 243 void brodi2(): 217–218, 243 void brodi3(): 217–218, 243 void plave(): 192, 218, 243 void dovody /*kra_barvy*/ (): 218–220
218
39 Modul kra barvy
Program kraluk
82: } 83: zmenanip(panacek, anip); 84: }
Kromě vody, ve které se dá brodit, je ve hře ještě voda, kde panáčka unáší proud. Barvy této vody jsou čtyři. Barva nebvoda1 táhne panáčka doleva nahoru, barva nebvoda2 táhne panáčka doprava nahoru, barva nebvoda3 táhne panáčka doprava dolů a barva nebvoda4 ho táhne doleva dolů. To, že je barva jednou z těchto čtyř, poznám tím, že má v položce prichfunc funkci topise. Tato funkce dá panáčkovi správný směr a animaci a znemožní jeho ovládání. Také mu přiřadí nulovou Z-kovou souřadnici, aby proplouval pod mostem. kra_barvy.c 98: void topise (kq_postava *post, kq_color *nova, kq_color *stara) 99: { 100: if(stara->prichfunc != topise){ 101: dovody(topeni); 102: post->tim->cas = 1; 103: nuluj_z(post, stara, nova); 104: ovlpost = NULL; 105: } 106: 107: if(nova == nebvoda1 || nova == nebvoda2) post->yy = -1; 108: if(nova == nebvoda2 || nova == nebvoda3) post->xx = 1; 109: if(nova == nebvoda3 || nova == nebvoda4) post->yy = 1; 110: if(nova == nebvoda4 || nova == nebvoda1) post->xx = -1; 111: }
Při odchodu z barvy vody je obvykle nastavena panáčkovi opět jeho původní animace, což provede funkce sucho. Aby byla animace topeni správně animována, je třeba, aby při změně barvy nebezpečné vody, nebyla postavě ani na okamžik přiřazena jiná animace, protože by to restartovalo timer, který topení animuje. kra_barvy.c 63: void sucho (kq_postava *post, kq_color *stara, kq_color *nova) 64: { 65: if(nova->prichfunc == topise) return; 66: 67: zmenanip(panacek, chozeni); 68: if(stara->prichfunc == topise){ 69: ovlpost = post; 70: post->xx = post->yy = 0; 71: normal_z(post, stara, nova); 72: post->tim->cas = 2; 73: } 74: }
Když panáček vstoupí na hnědý břeh nebezpečné řeky (barva breh), je vyhledáno nejbližší políčko, ve kterém je nebezpečná voda, a na toto políčko je panáček přesunut. To zařídí funkce paddovody. kra_barvy.c 113: void paddovody (kq_postava *post, kq_color *nova, kq_color *stara) 114: { 115: int i, x, y, smer; 116: kq_color *mpxl; 117: 118: for(i=0; i<mapa.sirka; i++){ 119: x=post->x+i; 120: y=post->y+i; 121: smer = NAHORU; 122: for(;;){ 123: mpxl = mappixel(mapa, x, y); 124: if(mpxl && mpxl->prichfunc == topise){ 125: post->x = x; 126: post->y = y; 127: topise (post, mpxl, nova);
kq_color *nebvoda1: 217–219 kq_color *nebvoda2: 217–219 kq_color *nebvoda3: 217–219 kq_color *nebvoda4: 217–219 void topise(): 217–219 void sucho(): 192, 218–219 kq_color *breh: 217, 220 void paddovody(): 217, 219
219
39 Modul kra barvy
Program kraluk
128: if(stara == zem || stara == most_col) popup_info("danger water"); 129: return; 130: } 131: if(smer == NAHORU && y == post->y-i) smer = VLEVO; 132: if(smer == VLEVO && x == post->x-i) smer = DOLU; 133: if(smer == DOLU && y == post->y+i) smer = VPRAVO; 134: if(smer == VPRAVO && x == post->x+i) break; 135: 136: switch(smer){ 137: case NAHORU: y--; break; 138: case VLEVO: x--; break; 139: case DOLU: y++; break; 140: case VPRAVO: x++; break; 141: } 142: } 143: } 144: 145: warning("paddovody: voda nenalezena"); 146: }
Když se panáček snaží vejít na půdu s kytičkami, spustí se funkce bachakytky, která vyskočí s oknem, že tam nemá chodit. kra_barvy.c 148: void bachakytky (kq_postava *post, kq_color *nova, kq_color *stara) 149: { 150: popup_info("flowers warn"); 151: }
Na políčku pol[[2][3] se vyskytuje submapa most_sm, která je obvykle schovaná, aby mohl panáček chodit za mostem a plavat pod mostem. Když vejde na most, spustí se funkce prich_most, která submapu odschová a dá panáčkovi takovou Z-kovou souřadnici, aby byl vidět před mostem. kra_barvy.c 153: void prich_most (kq_postava *post, kq_color *nova, kq_color *stara) 154: { 155: if(!most_sm){ 156: warning("prich_most: most_sm neni nacteny"); 157: return; 158: } 159: 160: unhidesubmap(most_sm); 161: post_z(post, 0,0,500); 162: }
Když odejdu z mostu, vrátí se Z-ková souřadnice zpátky a most_sm se opět schová. To provede funkce odch_most. V případě, že panáček spadl z mostu do vody, je posunut dolů. kra_barvy.c 164: void odch_most (kq_postava *post, kq_color *stara, kq_color *nova) 165: { 166: int x, y; 167: 168: if(!most_sm){ 169: warning("odch_most: most_sm neni nacteny"); 170: return; 171: } 172: 173: hidesubmap(most_sm); 174: normal_z(post, stara, nova); 175: 176: if(nova == breh){ 177: x = post->x; 178: y = post->y; 179: 180: while(smpixel(most_sm,x,y) == breh) y++; 181: y--; 182: if(y > post->y) post->y = y; void bachakytky(): 192, 220 void odch_most(): 194, 220
kq_submap *most_sm: 194, 220, 243–244
220
void prich_most(): 194, 220
39 Modul kra barvy
Program kraluk
183: } 184: }
Dále stojí za povšimnutí, co se stane při vstoupení panáčka na teleport. V takovém připadě se spustí timer teletim. kra_barvy.c 236: void telestart (kq_postava *post, kq_color *nova, kq_color *stara) 237: { 238: if(teletim){ 239: znictimer(teletim); 240: warning("teletim neni NULLovy"); 241: } 242: teletim = vytvortimer(&teleportuj, pinnull, 50+random()%200, -20, 0, 0, 0); 243: teletim->cas = 4; 244: }
Při odejití z teleportu je teletim opět zničen. kra_barvy.c 246: void teleend (kq_postava *post, kq_color *stara, kq_color *nova) 247: { 248: if(teletim) znictimer(teletim); 249: else warning("teletim je NULLovy"); 250: teletim = NULL; 251: }
Timer teletim opakovaně spouští funkci teleportuj. Nejprve ji spustí za čas mezi padesáti a dvě stě padesáti framy. Dále už je spouštěn jednou za čtyři framy. Když je funkce teleportuj spuštěna poprvé (což pozná podle toho, že ještě není vytvořený telepost), vytvoří postavu telepost na stejném místě, jako je panáček, a znemožní panáčkovi se hýbat. Když má postava telepost směr NAHORU, znamená to, že její stav animace má stoupat. Když už stav animace dosáhne čísla 12, změní se políčko a do směru telepost je dosazeno DOLU, takže se stav animace bude nadále snižovat. Když se sníží na nulu, zničí telepost a umožní panáčkovi se opět pohybovat. kra_barvy.c 186: void teleportuj () 187: { 188: if(telepost == NULL){ 189: popup_info("teleport"); 190: ovlpost = NULL; 191: panacek->xx = panacek->yy = 0; 192: panacek->barvy = 0; 193: telepost = vytvorpost(panacek->x, panacek->y, NAHORU, 0, 0, 0, 0); 194: normal_z(telepost, NULL, NULL); 195: telepost->z += 0.2; 196: telepost->barvy = 0; 197: if(hvezdicka->inv) zmenanip(telepost, teleanip2); 198: else zmenanip(telepost, teleanip); 199: } 200: else if(telepost->smer == NAHORU){ 201: if(telepost->animstav < 14){ 202: telepost->animstav++; 203: if(telepost->animstav == 9) hidepost(panacek); 204: } 205: else if(!telepost->hide) hidepost(telepost); 206: else{ 207: if(hvezdicka->inv){ 208: popup_info("hvezda pryc"); 209: predmetnull(hvezdicka); 210: kql_square(panacek, pol[6][4], 80, 20, 0, 0, 0); 211: } 212: else kql_square(panacek, skala1, 83, 64, 0, 0, 0); 213: znak = 0; 214: posunpost(telepost, panacek->x, panacek->y); 215: telepost->smer = DOLU; 216: } kq_timer *teletim(): 217, 221–222, 243–244 telepost: 216–217, 221–222, 243–244
void teleportuj(): 221, 244
221
kq_postav
39 Modul kra barvy 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: }
Program kraluk
} else{ if(telepost->hide) unhidepost(telepost); else if(telepost->animstav > 0){ telepost->animstav--; if(telepost->animstav == 9) unhidepost(panacek); } else{ znictimer(aktutimer); teletim = NULL; znicpost(telepost); telepost = NULL; panacek->barvy = 1; ovlpost = panacek; } } if(telepost) zmenapost(telepost);
Když panáček vejde pod kokos, spustí se funkce padejkokos, která založí timer, který opakovaně posouvá kokos k zemi. Funkce padejkokos navíc upraví předmět kokos tak, aby se, když odejdu a vrátím se, ležel již kokos na zemi. kra_barvy.c 313: void padejkokos (kq_postava *post, kq_color *nova, kq_color *stara) 314: { 315: zmenprnazev(kokos, "kokrap"); 316: znicsubmap(kokos->post->submap); 317: kokos->post->submap = NULL; 318: kokos->pix_y = 85; 319: kokos->sm_x = 21; 320: kokos->sm_y = 102; 321: vytvortimer(kokpadstep, pinnull, 1, -1, 46, 1, 0); 322: }
Funkce kokpadstep posouva kokos směrem k zemi. Při padání kokosu jsou specifické dva okamžiky. První je, když položka opakovani aktuálního timeru je rovna dvaceti. V takovém případě je vytvořena submapa, která brání panáčkovi vstoupit do místa, kde padá kokos. Pokud se již panáček pod kokosem nalézá, je zničen. Druhý významný okamžik je, když položka opakovani timeru je rovna nule. V takovém případě je kokos nakřápnut a je mu přiřazena ta dříve vytvořená submapa, takže již jde sebrat. kra_barvy.c 324: void kokpadstep () 325: { 326: kq_animpost *anip; 327: 328: if(aktutimer->opakovani == 0){ 329: anip = kokos->post->animace; 330: zmenanip(kokos->post, nactianip(-50, -85, "kokrap", 1,0,1,0,1)); 331: posunpost(kokos->post, 0, 0); 332: kokos->post->submap = prvsubmap; 333: return; 334: } 335: if(aktutimer->opakovani == 20){ 336: vytvorsubmap(21, 102, 5, "kokrap", 1, 0); 337: if(aktupixel() == zed){ 338: popup_info("kokos bum"); 339: znicpost(panacek); 340: panacek = ovlpost = NULL; 341: } 342: } 343: posunpost(kokos->post, 0, kokos->post->y+2); 344: }
Když panáček vejde na okraj skály, žebříku, schodů nebo jámy, spustí se funkce skalopada, která zařídí, že panáček spadne. Tato funkce zruší možnost ovládat panáčka a do proměnné panacek void padejkokos(): 196, 222
void kokpadstep(): 222, 244
222
void skalopada(): 217, 223, 234, 243
39 Modul kra barvy
Program kraluk
dosadí NULL. Panáčkovi přiřadí animaci padani a zlokální ho. Pro padání jsou tři barvy, které se ovšem liší jen Z-kovou souřadnicí, která se panáčkovi přiřadí. V barvě skalopad1 nastavím z = -3, v barvě skalopad2 nastavím z = -1 a v barvě skalopad3 nastavím z = 1. Funkce skalopada je zavolána i na spodku žebříku. V takovém případě však panáček jednoduše seskočí (objeví se dole). kra_barvy.c 253: void skalopada (kq_postava *post, kq_color *nova, kq_color *stara) 254: { 255: if(post != panacek) return; 256: 257: if(aktupol == pol[0][1]){ 258: normal_z(panacek, NULL, NULL); 259: zmenanip(panacek, chozeni); 260: panacek->y = 52; 261: if(jezibaba) jezichytej(); 262: return; 263: } 264: 265: if(panacek->animace == lezeni){ 266: if(aktupol == skal_zebr1 && jezibaba && jezibaba->animace == jezianip){ 267: znicpost(jezibaba); 268: jezinull(); 269: popup_info("pada z houp"); 270: } 271: else popup_info("pada z zebriku"); 272: } 273: else if(aktupol == pol[7][3]) popup_info("pada do diry"); 274: else if(aktupol == schody1 || aktupol == schody2) popup_info("pada ze schodu"); 275: else popup_info("pada ze skaly"); 276: 277: if(post->animace == brnanip){ 278: post->tim->cas = 3; 279: popup_info("pada brn"); 280: predmetnull(brneni); 281: } 282: 283: zmenanip(post, padani); 284: post->lokalni = 1; 285: post->barvy = post->zdi = 0; 286: post->xx = 0; 287: post->yy = 3; 288: post->xz = panacek->yz = 0; 289: if(nova == skalopad1) post->z = -3; 290: else if(nova == skalopad2) post->z = -1; 291: else panacek->z = 1; 292: ovlpost = NULL; 293: panacek = NULL; 294: if(jezibaba) jezivzdej(); 295: }
Kdyz panáček vstoupí do plamenů na skále (barva ohen), je zavolana funkce shor, která panáčka zlikviduje za předpokladu, že na sobě nemá brnení. Tato funkce je zavolána, i když do plamenů vstoupí ježibaba. V takovém případě však přenechá práci funkci jezishor. kra_barvy.c 297: void shor (kq_postava *post, kq_color *nova, kq_color *stara) 298: { 299: if(post == jezibaba){ 300: jezishor(); 301: return; 302: } 303: 304: if(post->animace != brnanip){ 305: popup_info("shorel jsi"); 306: ovlpost = NULL;
kq_color *skalopad1: 217, 223 kq_color *skalopad2: 217, 223 kq_color *skalopad3: 217, 234 kq_color *ohen: 211, 217, 230–232 void shor(): 211, 217, 223, 234
223
39 Modul kra barvy
Program kraluk
307: vytvortimer(znicpost, pinpointer(panacek), 0, 100, 1, 0, 0); 308: panacek = NULL; 309: if(jezibaba) jezivzdej(); 310: } 311: }
Když se panáček přiblíží ke lvům, spustí se funkce levchyt a jsou dvě možnosti, co se stane. Pokud má u sebe zapálenou svíčku, tak lvi zkamení a panáčkovi vypadne z inventáře kamínek. Pokud zapálenou svíčku nemá, je zničen. kra_barvy.c 346: void levchyt (kq_postava *post, kq_color *nova, kq_color *stara) 347: { 348: if(lvistav) return; 349: if(svicka->inv && svicka->stav){ 350: vytvorwidget( 5, 67, 62.2, nactikqXPM("kamenlev1", 1), 1, 0); 351: vytvorwidget( 76, 66, 62.2, nactikqXPM("kamenlev2", 1), 1, 0); 352: lvistav = 1; 353: popup_info("zkamenel lev"); 354: znak = ’k’; 355: if(kaminek->inv){ 356: predmetnull(kaminek); 357: kaminek->slovo->kontext++; 358: kamen = vytvorpost(66, 91, NAHORU, 0, 0, 1, 0); 359: zmenanip(kamen, nactianip(14, 21, "kamen", 1, 0, 1, 0, 1)); 360: normal_z(kamen, NULL, NULL); 361: post_submap(kamen, "kamen", 18, 13, 5); 362: popup_info("vypad kamen"); 363: } 364: } 365: else{ 366: popup_info("chytil lev"); 367: vytvortimer(znicpost, pinpointer(panacek), 0, 100, 1, 0, 0); 368: panacek = NULL; 369: ovlpost = NULL; 370: } 371: }
Funkce barvapolic je použita pro přechod na jiné políčko jinak než přes okraj. Tato funkce je využita pro vstup do hradu, do dřevěné chaloupky, do jeskyně a z jezkyně a také pro pád před peklo. kra_barvy.c 373: void barvapolic (kq_postava *post, kq_color *nova, kq_color *stara) 374: { 375: znak = 0; 376: if(aktupol == pol[5][1]){ 377: kql_square(panacek, vdrevchal, panacek->x+5, -1, 0, 1, 1); 378: znak = 0; 379: popup_info("drevchal odmena"); 380: } 381: else if(aktupol == lvi){ 382: popup_info("pada pred peklo"); 383: panacek->xx = panacek->yy = 0; 384: kql_square(panacek, peklbrana, 95, 7, 0, 0, 0); 385: lev->kontext--; 386: znak = 0; 387: } 388: else if(aktupol == schody2){ 389: kql_square(panacek, pol[0][0], 80, 45, 0, 0, 0); 390: znak = ’j’; 391: post_z(panacek, 0, 0, 10); 392: } 393: else if(aktupol == pol[0][0]){ 394: kql_square(panacek, schody2, 3, 14, 0, 0, 0); 395: normal_z(panacek, NULL, NULL); 396: znak = 0; 397: } void levchyt(): 199, 224
void barvapolic(): 217, 224
224
40 Modul kra jp
Program kraluk
398: else if(aktupol == pol[4][3]){ 399: kql_square(panacek, vzamku1, 55, -1, 0, 1, 0); 400: znak = 0; 401: } 402: }
Funkce predTV zobrazí královo napomenutí o překážení před televizí. kra_barvy.c 404: void predTV (kq_postava *post, kq_color *nova, kq_color *stara) 405: { 406: popup_info("pred TV"); 407: }
40 Modul kra jp Tento modul manipuluje s postavou jinapost. Tato postava může být Lotrandem (na políčku pol[4][1]), Maruškou (na políčku pol[3][6]), Ladou (na políčku pol[7][0]), Krasomilou (na políčku pol[6][6]) nebo jelenem (na políčku pol[2][2]). Jelena má ovšem na starosti modul kra jezin. Postavu jinapost (kromě jelena samozřejmě) založí funkce start_jp. kra_jp.c 3: void start_jp (kq_policko *opol, int smer, kq_policko *npol) 4: { 5: if(rand()%2 && npol != pol[4][1]) return; 6: 7: kq_animpost *anip; 8: int x, y, cas; 9: void (*auto_func)(kq_postava *post); 10: 11: auto_func = auto_random; 12: if(npol == pol[7][0]){ 13: if(makozisek) return; 14: cas = 50; 15: anip = nactianip(9, 40, "shvezdou", 4, 0, 0, 0, 1); 16: x = 0; y = 90; 17: } 18: else if(npol == pol[3][6]){ 19: if(dostalkyt) return; 20: cas = 50; 21: anip = nactianip(9, 40, "maruska", 4, 0, 0, 0, 1); 22: x = 0; y = 90; 23: } 24: else if(npol == pol[6][6]){ 25: if(dostalsvic) return; 26: cas = 0; 27: auto_func = pysna_random; 28: anip = nactianip(8, 45, "pysna", 1, 0, 0, 0, 1); 29: x = 16; y = 94; 30: } 31: else{ 32: cas = 0; 33: anip = nactianip(9, 42, "lotrando", 4, 0, 0, 0, 1); 34: x = 21; y = 93; 35: } 36: 37: jinapost = vytvorpost(x, y, VPRAVO, 3, -1, 1, cas); 38: jinapost->free_func = null_jp; 39: jinapost->zdi = 1; 40: jinapost->odraz = 1; 41: jinapost->barvy = 0; 42: jinapost->chyt_vzdal = 9; 43: jinapost->chyt_func = chyt_jp; 44: setchytpost(jinapost, panacek); 45: jinapost->xx = 1; void predTV(): 200, 225 kq_postava *jinapost: 213–215, 225–227, 229, 243, 245 start_jp(): 192–193, 196, 225
225
void
40 Modul kra jp 46: 47: 48: 49: 50: 51: 52: 53: 54: }
Program kraluk
jinapost->yy = -1; normal_z(jinapost, NULL, NULL); zmenanip(jinapost, anip); if(npol == pol[4][1]) autopost(jinapost, auto_clever, 0, 0); else autopost(jinapost, auto_func, 100, 20); post_submap(jinapost, "jinapost", 16, 16, 5); if(cas) vytvortimer(objev_jp, pinnull, cas, -1, 1, 1, 0); else objev_jp();
Postavy se kromě lotranda neobjeví vždy, ale jen s pravděpodobností 12 . Maruška se ovšem objeví pouze tehdy, když dostalkyt je nastaveno na false, Krasomila se objeví jen když dostalsvic je nastaveno na false a Lada se objeví jen když makozisek je false. Maruška a Lada se neobjeví okamžitě, ale až po padesáti framech. Funkce objev_jp nakonec postavu ukáže. Ovšem pouze v případě, že panáček není příliš blízko. kra_jp.c 56: void objev_jp () 57: { 58: if(post_vzdal(jinapost, panacek) > 9){ 59: osoba->kontext++; 60: if(aktupol != pol[4][1]){ 61: znak = ’p’; 62: divka->kontext++; 63: princezna->slovo->kontext++; 64: if(aktupol == pol[7][0]) lada->kontext++; 65: if(aktupol == pol[3][6]) maruska->kontext++; 66: if(aktupol == pol[6][6]) krasomila->kontext++; 67: } 68: else{ 69: lotrando->kontext++; 70: muz->kontext++; 71: } 72: unhidepost(jinapost); 73: } 74: }
Když se panáček příliš přiblíží postavě, zavolá se funkce chyt_jp, která postavu zastaví. Funkce chyt_jp je také zavolána, když Krasomila už dostala kytku a došla až do zámku. V takovém případě je zničena. kra_jp.c 76: void chyt_jp () 77: { 78: if(jinapost->autou_typ == AUTOU_SOUR){ 79: vytvortimer(znicpost, pinpointer(jinapost), 0, 100, 1, 0, 0); 80: return; 81: } 82: if(jinapost->tim) pausetimer(jinapost->tim); 83: if(jinapost->auto_tim) pausetimer(jinapost->auto_tim); 84: if(aktupol == pol[4][1]) popup_info("lotrando"); 85: if(aktupol == pol[6][6]) popup_info("pysna"); 86: vytvortimer(continue_jp, pinnull, 20, -1, -1, 1, 0); 87: }
Poté, co je postava zastavena, je každých 20 framů zavolána funkce continue_jp, která zkontroluje, zda je panáček už dostatečně daleko a v případě, že ano, ji opět rozpochoduje. kra_jp.c 89: void continue_jp () 90: { 91: if(!jinapost){ 92: znictimer(aktutimer); 93: return; 94: } 95: if(post_vzdal(jinapost, panacek) > 9){ char dostalkyt: 215, 225, 244–245 char dostalsvic: 215, 225, 244–245 244–245 void objev_jp(): 226, 245 void chyt_jp(): 225–226, 245 245
226
void makozisek: 214, 225, void continue_jp(): 226,
41 Modul kra jezin
Program kraluk
96: znictimer(aktutimer); 97: if(jinapost->auto_tim) unpausetimer(jinapost->auto_tim); 98: if(jinapost->tim) unpausetimer(jinapost->tim); 99: } 100: }
Lada a Maruška se pohybují náhodně a Lotrando jde přímo za panáčkem. Krasomila se také pohybuje téměř náhodně, ale neměla by odejít z ohrádky, která je na ní připravená. Mám pro ni tedy speciální funkci pysna_random, která nepošle postavu dolů v případě, že je její Y-ová souřadnice větší než 103. kra_jp.c 102: void pysna_random (kq_postava *post) 103: { 104: int smer; 105: 106: if(post->y >= 104) smer = rand()%5; 107: else smer = rand()%8; 108: 109: if(smer > 3) smer++; 110: 111: post->xx = smer%3-1; 112: post->yy = smer/3-1; 113: }
Při zničení postavy jinapost je zavolána funkce null_jp. Tato funkce do jinapost dosadí NULL a správně nastaví kontext slov a je zavolána i v případě zničení jelena. kra_jp.c 115: void null_jp (kq_postava *post) 116: { 117: jinapost = NULL; 118: if(post->hide) return; 119: 120: if(aktupol != pol[2][2]) osoba->kontext--; 121: if(aktupol == pol[7][0] || aktupol == pol[3][6] || aktupol == pol[6][6]){ 122: znak = 0; 123: divka->kontext--; 124: princezna->slovo->kontext--; 125: if(aktupol == pol[7][0]) lada->kontext--; 126: if(aktupol == pol[3][6]) maruska->kontext--; 127: if(aktupol == pol[6][6]) krasomila->kontext--; 128: } 129: else if(aktupol == pol[4][1]){ 130: lotrando->kontext--; 131: muz->kontext--; 132: } 133: }
41 Modul kra jezin V tomto modulu řeším scénu se Smolíčkem, jezinkami a jelenem. Když panáček vstoupí na políčko s pařezem (pol[2][1]), zavolá se funkce prich_jezin, která vytvoří jezinky a smolíčka. K tomuto políčku je přidáno slovo smolicek, takže to, zda tam smolíček je nebo není, se pozná podle toho, zda tam smolíček má nebo nemá kontext. Pokud tam smolíček není, tak mimo toto políčko je jeho kontext ještě menší než nula. Jezinky jsou vytvořeny v šestiúhelníku tak, aby kráčely po jeho obvodu po směru hodinových ručiček. kra_jezin.c 13: void prich_jezin (kq_policko *opol, int smer, kq_policko *npol) 14: { 15: int i, x, y, xx, yy, jsm; 16: kq_animpost *anip; 17: kq_postava *jezinka; 18: void pysna_random(): 225, 227, 245 227
void null_jp(): 225, 227, 229, 245
227
void prich_jezin(): 192,
41 Modul kra jezin 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: }
Program kraluk
if(smolicek->kontext <= 0){ znak = ’x’; return; } osoba->kontext++; vytvorwidget(81, 64, 63.2, nactikqXPM("smolicek", 1), 1, 0); xx = 1; yy = 0; x = 32; y = 26; anip = nactianip(9, 40, "jezinka", 4, 0, 0, 0, 1); for(i=0; i<8; i++){ if(xx > 0) jsm = VPRAVO; else if(xx < 0) jsm = VLEVO; else if(yy < 0) jsm = NAHORU; else jsm = DOLU; jezinka = vytvorpost(x, y, jsm, 3, -1, 1, 0); jezinka->xx = xx; jezinka->yy = yy; autopost(jezinka, auto_jezin, 75, 75); zmenanip(jezinka, anip); normal_z(jezinka, NULL, NULL); jezinka->chyt_vzdal = 7; jezinka->chyt_func = jezin_chyt; setchytpost(jezinka, panacek); x += 25*xx; y += 25*yy; jezinsmer(&xx, &yy); }
K tomu, aby jezinky správně chodily po obvodu, je na každou jezinku každých 75 framů zavolána funkce auto_jezin, která jezinku otočí o 45 stupňů. kra_jezin.c 53: void auto_jezin (kq_postava *post) 54: { 55: jezinsmer(&post->xx, &post->yy); 56: }
Pro otočení směru o 45 stupňů po směru hodinových ručiček mám po vzoru funkce primosmer funkci jezinsmer. kra_jezin.c 3: static void jezinsmer (int *xx, int *yy) 4: { 5: *yy += *xx; 6: *xx -= *yy-*xx; 7: if(!*xx || !*yy){ 8: *xx /= 2; 9: *yy /= 2; 10: } 11: }
Když jezinka chytí panáčka, je zavolána funkce jezin_chyt, která panáčka přesune před pařez. kra_jezin.c 58: void jezin_chyt (kq_postava *post) 59: { 60: popup_info("chytila jezinka"); 61: posunpost(panacek, 44, 84); 62: panacek->xx = panacek->yy = 0; 63: panacek->smer = DOLU; 64: }
void auto_jezin(): 228, 245 245
void jezinsmer /*kra_jezin*/ (): 228
228
void jezin_chyt(): 228,
42 Modul kra jezibaba
Program kraluk
Při odchodu z políčka s pařezem je zavolána funkce nullosobu, která vynuluje slovu osoba kontext. kra_jezin.c 97: void nullosobu (kq_policko *opol, int smer, kq_policko **npol, int *x, int *y) 98: { 99: osoba->kontext = 0; 100: }
Když panáček přijde na políčko s jelenem (pol[2][2]), je zavolána funkce prich_jelen. Tato funkce opět zjistí, stejně jako u Smolíčka, zda má jelen kontext. Pokud ano, vytvoří jelena do proměnné jinapost. kra_jezin.c 66: void prich_jelen (kq_policko *opol, int smer, kq_policko *npol) 67: { 68: if(jelen->kontext <= 0){ 69: znak = ’x’; 70: return; 71: } 72: 73: jinapost = vytvorpost(19, 57, NAHORU, 0, -1, 1, 0); 74: normal_z(jinapost, NULL, NULL); 75: zmenanip(jinapost, nactianip(17, 71, "jelen", 4, 0, 1, 0, 1)); 76: post_submap(jinapost, "jelen", 16, 7, 5); 77: jinapost->free_func = null_jp; 78: jinapost->tim = vytvortimer(jelen_step, pinnull, 3, -1, 0, 1, 0); 79: }
Když je jelen zobrazený, tak si hraje s kamenem. Je na něj tedy opakovaně volána funkce jelen_step, která posouvá animstav postavy jinapost mezi nulou a třemi. kra_jezin.c 81: void jelen_step () 82: { 83: if(jinapost->smer == NAHORU) jinapost->animstav++; 84: else jinapost->animstav--; 85: 86: if(jinapost->animstav == 0){ 87: jinapost->smer = NAHORU; 88: aktutimer->zbyva = 50; 89: } 90: else if(jinapost->animstav == 3){ 91: jinapost->smer = DOLU; 92: aktutimer->zbyva = 50; 93: } 94: zmenapost(jinapost); 95: }
42 Modul kra jezibaba V tomto modulu řeším sledování panáčka ježibabou, až do chycení panáčka nebo zničení ježibaby. V první fázi ježibaba normálně běží za panáčkem, potom se houpe žebřík a nakonec za panáčkem letí. Přitom, co jde nebo letí za panáčkem, má rychlost posunu za dva framy. Panáček se posune jednou za tři framy, takže ježibaba je jeden a půlkrát rychlejší. Když je uloupnut perníček, je zavolána funkce startjezi, která vytvoří lokální schovanou postavu jezibaba na souřadnicích JEZI_START_X, JEZI_START_Y. Po vytvoření je však do položky lokalni této postavy dosazena nula. To proto, abych ve funkci, která je spuštěna při příchodu panáčka na políčko, věděl, zda byla ježibaba před odchodem schovaná nebo ne. kra_jezibaba.c 3: #define JEZI_START_X 4: #define JEZI_START_Y
74 87
void nullosobu: 192, 229 void prich_jelen(): 193, 229 void jelen_step(): 229, 245 void startjezi(): 216, 230 kq_postava *jezibaba: 204–205, 209, 223–224, 230–235, 243–244 JEZI_START_X: 229–230, 232–233 JEZI_START_Y: 229–230, 232–233
229
42 Modul kra jezibaba
Program kraluk kra_jezibaba.c
15: void startjezi () 16: { 17: jezibaba = vytvorpost(JEZI_START_X, JEZI_START_Y, VLEVO, 2, -1, -1, 1); 18: jezibaba->zdi = jezibaba->barvy = 0; 19: jezibaba->lokalni = 0; 20: jezibaba->chyt_func = jezichyt; 21: jezichytej(); 22: vytvortimer(continuejezi, pinnull, 22, 0, 1, 1, 0); 23: zmenanip(jezibaba, jezianip); 24: autopost(jezibaba, &auto_clever, 0, 0); 25: normal_z(jezibaba, NULL, NULL); 26: pol_prichfunc = jeziprichpol; 27: otevridvere(); 28: }
Po vytvoření je založen timer jezitimer, který po určitém časovém úseku spustí continuejezi, což je funkce, která ježibabu odschová. kra_jezibaba.c 112: void continuejezi () 113: { 114: if(!panacek) return; 115: 116: if(aktupol == skal_zebr1 || aktupol == skal_zebr2) post_z(jezibaba, 0, 0, 200); 117: else normal_z(jezibaba, NULL, NULL); 118: 119: if(jezibaba->hide){ 120: osoba->kontext++; 121: jezislovo->kontext++; 122: } 123: 124: if(jezitimer){ 125: jezitimer = NULL; 126: if(aktupol == skala3){ 127: jezibaba->x = 85; 128: jezibaba->y = 108; 129: } 130: else{ 131: jezibaba->x = panacek->x; 132: if(aktupol == skala2) jezibaba->y = 0; 133: else jezibaba->y = mapa.vyska-1; 134: } 135: unhidepost(jezibaba); 136: if(mappixel(mapa, jezibaba->x, jezibaba->y) == ohen){ 137: jezishor(); 138: return; 139: } 140: if(jezibaba->auto_func != &auto_primo){ 141: jezibaba->auto_func = &auto_primo; 142: popup_info("jezi nevzdala"); 143: } 144: return; 145: } 146: jezil_x = jezibaba->x; 147: jezil_y = jezibaba->y; 148: unhidepost(jezibaba); 149: jezilastpol = NULL; 150: }
Když je vytvořená ježibaba, tak je při příchodu na nové políčko volána funkce jeziprichpol. Tato funkce přesune ježibabu na políčko, na kterém je panáček. Pokud je políčko, na které panáček přišel, políčkem, ze kterého naposledy odešel a měla by na něm tudíž být ježibaba (tedy políčko jezilastpol), je panáček ježibabou okamžitě chycen. Jinak je ježibaba objevena funkcí continuejezi až za dobu, za kq_timer *jezitimer: 230–231, 243–244 void continuejezi(): 230–232, 235, 244 void jeziprichpol(): 230–231, 244 kq_policko *jezilastpol: 230–233, 243–244
230
42 Modul kra jezibaba
Program kraluk
kterou by došla ke hraně, kterou panáček přešel mezi políčky. Při počítání tohoto času ovšem nejsou brány v úvahu zdi. Příslušný timer je opět uložen do jezitimer. Pokud už ježibaba letí na koštěti, je v timeru jezitimer počet framu, za který ježibaba přiletí na aktuální políčko. Změnou políčka se tento timer příslušně upraví, zmenší nebo zvětší. Na začátku, tedy po překonání houpajícího žebříku, je tento timer nastavený na 400 framu. kra_jezibaba.c 30: void jeziprichpol (kq_policko *odch, int smer, kq_policko *prich) 31: { 32: int i, x, y; 33: 34: if(jezibaba->animace == jezileti){ 35: if(prich == skala1 || prich == skala2 || prich == skala3) normal_z(jezibaba, NULL, NULL); 36: else post_z(jezibaba, 0,0,200); 37: if(jezibaba->hide){ 38: i = zjistitimer(jezitimer); 39: if(smer == NAHORU) i += 224; 40: if(smer == DOLU) i -= 224; 41: if(i >= 0) zmentimer(jezitimer, i, jezitimer->priorita); 42: else{ 43: znictimer(jezitimer); 44: jezitimer = NULL; 45: jezibaba->x = panacek->x; 46: jezibaba->y = -i/2-1; 47: if(odch != skala2) jezibaba->y = mapa.vyska - jezibaba->y; 48: unhidepost(jezibaba); 49: if(mappixel(mapa, jezibaba->x, jezibaba->y) == ohen) jezishor(); 50: if(jezibaba->auto_func != &auto_primo){ 51: jezibaba->auto_func = &auto_primo; 52: popup_info("jezi nevzdala"); 53: } 54: } 55: } 56: else{ 57: if(prich == skala2) i = mapa.vyska-jezibaba->y; 58: else i = jezibaba->y; 59: jezitimer = vytvortimer(continuejezi, pinnull, 2*i, -1, 1, 0, 0); 60: osoba->kontext--; 61: jezislovo->kontext--; 62: jezibaba->hide = 1; 63: } 64: return; 65: } 66: 67: if(prich != jezilastpol && jezibaba->hide){ 68: jezil_x = jezibaba->x; 69: jezil_y = jezibaba->y; 70: } 71: else{ 72: osoba->kontext--; 73: jezislovo->kontext--; 74: } 75: jezibaba->hide = 1; 76: 77: if(prich == skal_zebr1){ 78: jezilastpol = odch; 79: return; 80: } 81: if(prich == skal_zebr2){ 82: popup_info("nehoupa zebr"); 83: zmenanip(jezibaba, jezileti); 84: jezibaba->chyt_vzdal = 7; 85: jezichytej(); 86: jezibaba->barvy = 1; 87: jezilastpol = NULL; 88: jezitimer = vytvortimer(continuejezi, pinnull, 400, -1, 1, 0, 0); 89: return; 90: }
231
42 Modul kra jezibaba 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: }
Program kraluk
if(prich == pol[1][1]) otevridvere(); if(smer == NAHORU) i = jezibaba->y; else if(smer == DOLU) i = mapa.vyska-jezibaba->y-1; else if(smer == VLEVO) i = jezibaba->x; else if(smer == VPRAVO) i = mapa.sirka-jezibaba->x-1; if(prich == jezilastpol){ getchytsour(jezibaba, &x, &y); posunpost(jezibaba, x, y); unhidepost(jezibaba); return; } posunpost(jezibaba, panacek->x, panacek->y); jezilastpol = odch; vytvortimer(continuejezi, pinnull, i*2, -1, 1, 1, 0);
Když vejdu na políčko s chaloupkou, jsou otevřeny dveře chaloupky funkcí otevridvere. Tyto dveře jsou ve skutečnosti dvěma widgety a jednou submapou. kra_jezibaba.c 8: static void otevridvere () 9: { 10: vytvorwidget(124, 79, 86, nactikqXPM("zachaldver", 1), 1, 0); 11: vytvorwidget(125, 79, 92, nactikqXPM("otvchaldver", 1), 1, 0); 12: vytvorsubmap(60, 87, 1, "perdvere", 1, 0); 13: }
Když ježibaba chytí panáčka, je zavolána funkce jezichyt. V takovém připadě funkce chytí panáčka a vydá se na souřadnice, na kterých se naposledy objevila. To jsou souřadnice jezil_x a jezil_y. Když se tam dostane, je funkce jezichyt znovu spuštěna a přemístí ježibabu na políčko s chaloupkou. Potom jde ježibaba ke dveřím. Až k nim dojde, je funkce jezichyt zavolána potřetí. V takovém případě je zničena ježibaba a zavřeny dveře. Pokud je ježibaba na koštěti, po chycení panáčka vyletí nahoru, objeví se na políčku s chaloupkou a opět sletí dolů. V takovém případě ovšem nedoletí na souřadnice JEZI_START_X, JEZI_START_Y, ale JEZI_DOLET_X, JEZI_DOLET_Y. kra_jezibaba.c 5: #define JEZI_DOLET_X 6: #define JEZI_DOLET_Y
70 70 kra_jezibaba.c
152: void jezichyt (kq_postava *jezi) 153: { 154: int x, y; 155: 156: if(mappixel(mapa, jezibaba->x, jezibaba->y) == ohen) return; 157: if(panacek){ 158: jezi->lokalni = 0; 159: jezi->tim->lokalni = 0; 160: jezi->widget->lokalni = 0; 161: popup_info("jezichyt"); 162: znicpost(panacek); 163: ovlpost = panacek = NULL; 164: if(jezibaba->animace == jezileti){ 165: jezil_x = jezibaba->x; 166: jezil_y = 0; 167: post_z(jezibaba, 0, 0, jezibaba->widget->z); 168: jezibaba->xx = 0; 169: jezibaba->yy = -1; 170: autopost(jezibaba, NULL, 0, 0); 171: jezibaba->barvy = 0; void otevridvere /*kra_jezibaba*/ (): 230, 232–233 void jezichyt(): 230, 232, 244 int jezil_x: 230–233, 244–245 int jezil_y: 230–233, 244–245 JEZI_DOLET_X: 232–233 JEZI_DOLET_Y: 232–233
232
42 Modul kra jezibaba 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: }
Program kraluk
} } if(jezibaba->animace == jezianip){ x = JEZI_START_X; y = JEZI_START_Y; } else{ x = JEZI_DOLET_X; y = JEZI_DOLET_Y; } if(aktupol == pol[1][1]){ jezil_x = x; jezil_y = y; if(jezi->x == jezil_x && jezi->y == jezil_y){ vytvortimer(znicpost, pinpointer(jezi), 0, 100, 1, 0, 0); if(prvwidget == jezi->widget) znicwidget(prvwidget->next); else znicwidget(prvwidget); if(prvwidget == jezi->widget) znicwidget(prvwidget->next); else znicwidget(prvwidget); jezinull(); return; } } else if(jezi->x == jezil_x && jezi->y == jezil_y){ autopost(jezi, NULL, 0, 0); jezil_x = x; jezil_y = y; if(jezibaba->animace == jezileti){ jezi->xx = 0; jezi->yy = 1; post_z(jezi, 0,0, JEZI_START_Y+0.5); kql_square(jezi, pol[1][1], x, 0,0,0,0); } else{ jezi->xx = 1; jezi->yy = 0; kql_square(jezi, pol[1][1], 0, y, 0,0,0); } otevridvere(); } setchytsour(jezibaba, jezil_x, jezil_y); jezibaba->chyt_vzdal = 0;
Po zničení ježibaby je dobré vynulovat hodnoty související s ježibabou, aby fungovalo v pořádku ukládání pozice, což udělá funkce jezinull. kra_jezibaba.c 286: void jezinull () 287: { 288: jezibaba = NULL; 289: jezilastpol = NULL; 290: pol_prichfunc = NULL; 291: jezil_x = jezil_y = 0; 292: }
Když panáček vyleze na žebřík, ale je jěště na políčku pol[0][1], je spuštěna funkce jezicekej, takže ježibaba už nejde přímo za panáčkem, ale jde k žebříku. kra_jezibaba.c 219: void jezicekej () 220: { 221: setchytsour(jezibaba, 88, 52); 222: jezibaba->chyt_vzdal = 0;
void jezinull(): 223, 233–235
void jezicekej(): 209, 233
233
42 Modul kra jezibaba
Program kraluk
223: }
Když pak panáček opět sleze z žebříku, spustí se funkce jezichytej, která zařídí, že ježibaba opět pronásleduje panáčka. kra_jezibaba.c 225: void jezichytej () 226: { 227: setchytpost(jezibaba, panacek); 228: jezibaba->chyt_vzdal = 7; 229: }
Při vstupu na políčko skal_zebr1 je buď vytvořen widget visícího žebříku nebo je zavolána funkce houpejzebr, která vytvoří houpající se žebřík. kra_jezibaba.c 231: void houpejzebr () 232: { 233: vytvortimer(houp_step, 234: pinpointer(vytvorwidget(85, 0, 0, nactikqXPM("houpzebr", 1), 1, 0)), 235: 2, 1, 0, 1, 0); 236: vytvorsubmap(0, 0, 5, "houpzebr", 1, 0); 237: popup_info("houpa zebr"); 238: }
Houpající se žebřík je tvořen widgetem a submapou, které jsou posouvány každé dva framy o pět pixelů směrem dolů funkcí houp_step. Tato funkce dostane jako parametr widget, který má posunout. Když panáček spadne z houpajícího se žebříku a dopadá úplně dolů, zničí se jeho postava. V tom okamžiku funkce houp_step pozná, že už není na obrazovce žádná postava, a přestane houpat s žebříkem. Postava jezibaba totiž byla zničena už v okamžiku, kdy panáček začal padat. kra_jezibaba.c 240: void houp_step (kq_widget *wzebr) 241: { 242: int y; 243: 244: if(!prvpost){ 245: popup_info("co jezi"); 246: znicwidget(prvwidget); 247: vytvorwidget(94, 0, 0, nactikqXPM("zebrik", 1), 1, 0); 248: znictimer(aktutimer); 249: return; 250: } 251: 252: y = wzebr->y+5; 253: if(y > 0) y -= 150; 254: 255: posunwidget(wzebr, wzebr->x, y); 256: prvsubmap->y = y; 257: reloadmap(); 258: if(panacek && aktupixel() == skalopad3) 259: skalopada(panacek, NULL, NULL); 260: }
Funkce jezishor je zavolána v okamžiku, kdy ježibaba vletí do ohně a tudíž shoří. kra_jezibaba.c 262: void jezishor () 263: { 264: osoba->kontext--; 265: jezislovo->kontext--; 266: popup_info("jezi shor"); 267: vytvortimer(znicpost, pinpointer(jezibaba), 0, 100, 1, 0, 0); 268: jezinull(); 269: }
Funkce jezivzdej je zavolána v okamžiku, kdy je zničen panáček, takže ježibaba už nemá, koho pronásledovat. To se může stát jen v případě, že ježibaba už je na koštěti. Pokud není schovaná, tak void jezichytej(): 223, 230–231, 234 void houpejzebr(): 205, 234 void jezishor(): 223, 230–231, 234 jezivzdej: 223–224, 235
234
void houp_step: 234, 245
43 Modul kra krk
Program kraluk
vyletí nahoru a zmizí. Pokud je ježibaba schovaná, tak se ani neobjeví, protože se funkce continuejezi ukončí, pokud není panáček. kra_jezibaba.c 271: void jezivzdej () 272: { 273: autopost(jezibaba, NULL, 0, 0); 274: setchytsour(jezibaba, 0, 0); 275: if(jezibaba->hide) return; 276: post_z(jezibaba, 0, 0, jezibaba->widget->z); 277: jezibaba->barvy = 0; 278: jezibaba->xx = 0; 279: jezibaba->yy = -1; 280: setchytsour(jezibaba, 0,0); 281: jezibaba->chyt_func = NULL; 282: jezibaba->widget->lokalni = jezibaba->tim->lokalni = jezibaba->lokalni = 1; 283: jezinull(); 284: }
43 Modul kra krk V tomto modulu řeším zobrazování krkavců a Bohdanky. Jak na tom krkavci s Bohdankou jsou, určuje proměnná krkstav. Když je tato proměnná rovna jedné, jsou krkavci ještě stále krkavci a Bohdanka sedí před chaloupkou. Když krkstav == -1, jsou dveře do chaloupky otevřené. Když krkstav == 0, jsou už dveře do chaloupky zavřené. Při vstupu na políčko s krkavci je zavolána funkce prich_krk, která vytvoří krkavce. Do proměnné krksedi je uložena animace sedícího krkavce a do proměnné krkleti je uložena animace krkavce mávajícího křídly. kra_krk.c 13: void prich_krk (kq_policko *opol, int smer, kq_policko *npol) 14: { 15: kq_animpost *anip; 16: 17: if(krkavci->kontext <= 0){ 18: znak = ’x’; 19: return; 20: } 21: 22: krksedi = nactianip(7, 73, "krksedi", 1, 0, 1, 0, 1); 23: krkleti = nactianip(7, 93, "krkleti", 2, 4, 0, 1, 1); 24: 25: vytvor_krk(14, 46, anip); 26: vytvor_krk(25, 67, anip); 27: vytvor_krk(37, 85, anip); 28: vytvor_krk(53, 101, anip); 29: vytvor_krk(69, 84, anip); 30: vytvor_krk(81, 63, anip); 31: vytvor_krk(92, 50, anip); 32: 33: vytvortimer(plasptaky, pinnull, 10, 0, 0, 1, 0); 34: }
Tato funkce ovšem musí těch krkavců vytvořit sedm, takže pro vytvoření jednoho krkavce mám funkci vytvor_krk, která dostane souřadnice a animaci. kra_krk.c 3: static void vytvor_krk (int x, int y, kq_animpost *anip) 4: { 5: kq_postava *post; 6: 7: post = vytvorpost(x, y, DOLU, 0, 0, 1, 0); 8: zmenanip(post, krksedi); 9: normal_z(post, NULL, NULL);
char krkstav: 216, 235–237, 244–245 void prich_krk(): 192, 235 kq_animpost *krksedi: 235–236, 243, 245 kq_animpost *krkleti: 235–236, 243, 245 void vytvor_krk /*kra_krk*/ (): 235
235
43 Modul kra krk
Program kraluk
10: post->barvy = post->zdi = 0; 11: }
Aby krkavci působily živě, v okamžiku, když se k nějakému panáček přiblíží, se ten krkavec vznese do vzduchu. Každých deset framů projdu všechny krkavce a nastavím jim správnou animaci podle vzdálenosti od panáčka funkcí plasptaky. kra_krk.c 65: void plasptaky () 66: { 67: kq_postava *pom; 68: 69: for(pom = prvpost; pom; pom = pom->next) 70: if(pom != panacek){ 71: if(pom->chyt_func){ 72: znictimer(aktutimer); 73: return; 74: } 75: if(post_vzdal(pom, panacek) < 20) zmenanip(pom, krkleti); 76: else zmenanip(pom, krksedi); 77: } 78: }
Když dám krkavcům perník, spustí se funkce promenujkrk, která nastaví krkavce, aby měli animaci krkleti a chtěli se dostat na místo, na kterém právě je panáček, nepronásledují ovšem panáčka. Kromě toho funkce promenujkrk načte animaci odkrk, což jsou proměnění krkavci. Když se krkavci slétají na perník, není žádoucí, aby na ně byla aplikována funkce plasptaky. Proto se plašení krkavců vypne, jakmile funkce plasptaky shledá, že má nějaký krkavec nastavenou funkci chyt_func. kra_krk.c 80: void promenujkrk () 81: { 82: kq_postava *pom; 83: 84: odkrk = nactianip(9, 40, "odkrk", 8, 0, 1, 0, 0); 85: krkstav = -1; 86: 87: krkleti->y = 73; 88: for(pom = prvpost; pom; pom = pom->next) 89: if(pom != panacek){ 90: setchytsour(pom, panacek->x, panacek->y); 91: pom->chyt_func = krk_chyt; 92: zmenanip(pom, krkleti); 93: autopost(pom, auto_primo, 0, 0); 94: pom->tim = vytvortimer(jdipost, pinpointer(pom), 3, -1, 0, 1, 0); 95: } 96: 97: popup_info("promen krk"); 98: }
Poté, co krkavec doletí na místo, kde stál panáček, když mu dal perník, spustí se na něj funkce krk_chyt, která ho promění v člověka a nasměruje doprava. kra_krk.c 100: void krk_chyt (kq_postava *post) 101: { 102: krkavci->kontext--; 103: zmenanip(post, odkrk); 104: post->xx = 1; 105: post->yy = 0; 106: autopost(post, NULL, 0, 0); 107: }
Při odchodu z políčka s krkavci je zavolána funkce null_krk, která dosadí NULL do animací krkavců. void plasptaky(): 235–236, 245 void promenujkrk(): 214, 236 void krk_chyt(): 236, 245 void null_krk(): 192
236
kq_animpost *odkrk: 236, 243, 245
44 Modul kra provaz
Program kraluk
Když panáček přijde na políčko s dřevěnou chaloupkou, spustí se funkce prich_bohd, která podle krkstav zobrazí bohdanku nebo otevře dveře. kra_krk.c
36: void prich_bohd (kq_policko *opol, int smer, kq_policko *npol) 37: { 38: if(!krkstav){ 39: znak = ’z’; 40: return; 41: } 42: 43: if(krkstav > 0){ 44: vytvorwidget( 81, 102, 95.2, nactikqXPM("smutnab", 1), 1, 0); 45: osoba->kontext++; 46: divka->kontext++; 47: bohdanka->kontext++; 48: } 49: else{ 50: znak = ’o’; 51: vytvorwidget(124, 88, 90.2, nactikqXPM("otvchaldrev", 1), 1, 0); 52: vytvorsubmap( 64, 90, 15, "dodrchal", 1, 0); 53: } 54: }
Funkce odch_bohd je spuštěna při odchodu z políčka s dřevěnou chaloupkou. kra_krk.c 56: void odch_bohd (kq_policko *opol, int smer, kq_policko **npol, int *x, int *y) 57: { 58: if(krkstav > 0){ 59: osoba->kontext--; 60: divka->kontext--; 61: bohdanka->kontext--; 62: } 63: }
Když panáček odejde z dřevěné chaloupky, měl by se objevit přede dveřmi této chaloupky. Pro to je zavolána funkce zdrchal. kra_krk.c 109: void zdrchal (kq_policko *opol, int smer, kq_policko **npol, int *x, int *y) 110: { 111: *x -= 5; 112: *y = 91; 113: }
44 Modul kra provaz V tomto modulu je řešeno, jak Bobeš tahá panáčka a jiné věci provazem nahoru a dolů. Většina tohoto tahání je v políčku lvi, i když na začátku je panáčak spouštěn na políčku pol[7][3]. Aktuální stav tahání určuje proměnná lvistav, která rovněž ukazuje, zda jsou lvi již zkamenělí. To zda jsou lvi zkamenělí určuje lvistav%2. V případě, že je lvistav lichý, lvi zkamenělí jsou a když je sudý, tak nejsou. Pokud lvistav nabývá hodnoty 0 nebo 1, je provaz v klidu a čeká až se na něj něco přiváže. Pokud je lvistav roven 2 nebo 3, je právě provazem něco (například panáček) spouštěno dolů a když je v proměnné lvistav hodnota 4 či 5, je něco taháno nahoru. Hodnota 2 nebo 3 je použita i v okamžiku, kdy panáček nebo kámen není spouštěn, ale padá. Celkem existují tři věci, které mohou být tahány provazem. Je to princezna, kaminek (zvětšený) a panacek. Pro animaci tahání provazu je použita funkce provazstep. Tato funkce má jako parametr postavu, kterou posunuje. Posouvání této postavy je řešeno pouze pomocí změny Y-ové souřadnice a není k tomu využívána funkce posunpost. Pokud posunuje panáčka, tak je jako timer animace použita položka tim postavy panacek.
void prich_bohd(): 193, 237 void odch_bohd(): 193, 237 void zdrchal(): 199, 237 unsigned int lvistav: 224, 237–239, 244–245 void provazstep()
237
44 Modul kra provaz
Program kraluk
kra_provaz.c 118: void provaz_step (kq_postava *post) 119: { 120: if(aktupol == pol[7][3] && post->y == 100){ 121: kql_square(post, lvi, 97, 0, 0, 0, 0); 122: divka->kontext++; 123: osoba->kontext++; 124: lev->kontext++; 125: znak = 0; 126: post->y = -35; 127: post->z = 76; 128: wprovaz = vytvorwidget(195, -159, 75, nactikqXPM("provaz", 1), 1, 0); 129: } 130: else if(lvistav < 4){ 131: if(aktutimer->cas == 1){ 132: if(post->y > 50){ 133: if(post == kamen){ 134: kamen = NULL; 135: znictimer(aktutimer); 136: } 137: else{ 138: panacek = ovlpost = NULL; 139: } 140: znicpost(post); 141: vytvorwidget(180, 107, 0, nactikqXPM("dira", 1), 1, 0); 142: if(!panacek) vytvorsubmap(90, 72, 5, "dira", 1, 0); 143: else if(smpixel(vytvorsubmap(90, 72, 5, "dira", 1, 0), panacek->x, panacek->y)){ 144: znicpost(panacek); 145: panacek = ovlpost = NULL; 146: popup_info("kamen na hlavu"); 147: } 148: return; 149: } 150: post->y += 2; 151: anip_step(post); 152: zmenapost(post); 153: return; 154: } 155: if(post){ 156: post->y++; 157: zmenapost(post); 158: } 159: if(wprovaz && wprovaz->y == -74 && kamen && post == kamen){ 160: kamen->submap->x = 96-kamen->sm_x; 161: kamen->submap->y = 75-kamen->sm_y; 162: 163: unhidesubmap(kamen->submap); 164: 165: prycodzdi(); 166: } 167: if(wprovaz) posunwidget(wprovaz, wprovaz->x, wprovaz->y+1); 168: if(aktupol == pol[7][3] && post->y == 100) 169: zmentimer(aktutimer, SPUSTCAS, aktutimer->priorita); 170: if(aktupol == lvi && wprovaz->y == -64){ 171: if(post){ 172: post->x = 96; 173: post->y = 75; 174: post->xx = post->yy = 0; 175: normal_z(post, NULL, NULL); 176: if(post == panacek){ 177: zmenanip(post, chozeni); 178: post->smer = VPRAVO; 179: aktutimer->funkce = jdipost; 180: prycodzdi(); 181: } 182: else znictimer(aktutimer); 183: } 184: else znictimer(aktutimer);
238
44 Modul kra provaz
Program kraluk
185: lvistav -= 2; 186: } 187: } 188: else{ 189: post->y--; 190: zmenapost(post); 191: if(wprovaz) posunwidget(wprovaz, wprovaz->x, wprovaz->y-1); 192: if(post->y == -55){ 193: if(!princezna->inv && !princezna->pol && 194: (post == panacek || post == kamen)){ 195: aktutimer->cas = 1; 196: znicwidget(wprovaz); 197: wprovaz = NULL; 198: zmentimer(aktutimer, SPUSTCAS/2, aktutimer->priorita); 199: } 200: zmentimer(aktutimer, SPUSTCAS, aktutimer->priorita); 201: } 202: if(post->y == -56){ 203: if(aktutimer->cas == 1){ 204: zmentimer(aktutimer, SPUSTCAS/6, aktutimer->priorita); 205: if(post == panacek){ 206: zmenanip(post, padani); 207: popup_info("pada panac"); 208: } 209: else popup_info("pada kamen"); 210: } 211: else{ 212: zmentimer(aktutimer, SPUSTCAS, aktutimer->priorita); 213: if(post == kamen) popup_info("vraci kamen"); 214: else if(post == panacek) popup_info("vraci panacka"); 215: else{ 216: popup_info("bere princeznu"); 217: znicpost(post); 218: aktutimer->parametr = pinpointer(NULL); 219: } 220: } 221: lvistav -= 2; 222: } 223: } 224: }
Zajímavé je, co se děje, když doposunuje to, co posunuje, úplně dolů nebo úplně nahoru. Na políčku pol[7][3] je posunováno jenom dolů a jenom panáček. V případě, že je panáček doposunován dolů, je změněno aktuální políčko na lvi. Přitom je vytvořen do proměnné wprovaz, což je widget, s kterým je posouváno stejně jako s postavou. Když je pak panáček doposunován až dolů, nastaví se mu, aby mohl být opět ovládán. Když je potom přivázáno k provazu něco jiného než princezna, je to vysunuto nahoru. Potom timer chvíli počká a snese postavu opět dolů. Mohlo by se stát, že je kámen snesen na panáčka nebo panáček na kámen. V takovém případě je panáček odsunut od zdi funkcí prycodzdi. Submapa kamene je při spouštění aktivována o něco dříve než je kámen dosesunut na zem. kra_provaz.c 5: static void prycodzdi () 6: { 7: int i; 8: 9: if(aktupixel() == zed) 10: for(i=1;; i++){ 11: if(mappixel(mapa, panacek->x+i, panacek->y) != zed){ 12: posunpost(panacek, panacek->x+i, panacek->y); 13: break; 14: } 15: if(mappixel(mapa, panacek->x-i, panacek->y) != zed){ 16: posunpost(panacek, panacek->x-i, panacek->y); 17: break; kq_widget *wprovaz(): 238–240, 244–245
void prycodzdi /*kra_provaz*/ (): 238–239
239
44 Modul kra provaz 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: }
Program kraluk
} if(mappixel(mapa, panacek->x, panacek->y+i) != zed){ posunpost(panacek, panacek->x, panacek->y+i); break; } if(mappixel(mapa, panacek->x, panacek->y-i) != zed){ posunpost(panacek, panacek->x, panacek->y-i); break; } }
Když je vytažena princezna, je pak dolů sesunut už jen prázdný provaz. V takovém případě pak funkce provaz_step dostává jako parametr NULL. V případě, že poté, co byla nahoru vytažena princezna, tedy když není v inventáři ani na políčku, je nahoru vytaženo něco dalšího, widget wprovaz je zničen a předmět, který byl tahán nahoru, padá dolů. Při dopadu je vytvořena díra, která je zobrazena jako widget i jako submapa. Pokud nyní kámen spadne panáčkovi na hlavu, není panáček odsunut, nýbrž zničen. Když hráč napíše, aby program něco přivázal, spustí se funkce privaz. Tato funkce může dostat slovo předmětu princezna nebo předmětu kaminek, nebo může dostat NULL. Když dostane NULL, znamená to, že přivázán má být panáček. kra_provaz.c 226: void posun (int pocet, kq_word **slova) 227: { 228: int xx, yy; 229: 230: if(!panacek){ 231: popup_info("nemuzes nic"); 232: return; 233: } 234: if(!kamen || (pocet && slova[0] != kaminek->slovo)){ 235: popup_info("neni duvod"); 236: return; 237: } 238: if(smpixel(kamen->submap, panacek->x, panacek->y) != dosahpredmet){ 239: popup_info("_too far"); 240: return; 241: } 242: 243: xx = kamen->x - panacek->x; 244: yy = kamen->y - panacek->y; 245: 246: if(abs(xx) > abs(yy)){ 247: if(xx > 0){ 248: xx = 5; 249: panacek->smer = VPRAVO; 250: } 251: else{ 252: xx = -5; 253: panacek->smer = VLEVO; 254: } 255: yy = 0; 256: } 257: else{ 258: xx = 0; 259: if(yy > 0){ 260: yy = 5; 261: panacek->smer = DOLU; 262: } 263: else{ 264: yy = -5; 265: panacek->smer = NAHORU; 266: } 267: } void privaz(): 206
240
44 Modul kra provaz
Program kraluk
268: 269: zmenapost(panacek); 270: if(posunpost(kamen, kamen->x+xx, kamen->y+yy)) popup_info("posunul kamen"); 271: else popup_info("posun do zdi"); 272: }
Když se panáček přiblíží ke lvům se zapálenou svíčkou, je vytvořena postava kamen. Tato postava je jednou z věcí, které jdou přivázat. K tomu, aby mohla být přivázána je třeba ji dostat do dostatečné blízkosti provazu. Přivázat kámen jde jen v případě, že panáček stojí dostatečně blízko kamenu a postava kamen je dostatečně blízko provazu. Funkce posun je zavolána, když hráč napíše, aby program něco posunul. Jediný předmět, který ovšem má smysl posouvat je kámen. V takovém připadě, pokud je panáček dostatečně blízko kamenu, je kámen posunut jedním ze směrů NAHORU, DOLU, DOPRAVA, DOLEVA o pět pixelů v mapě. Směr je spočítán tak, aby se kámen posunul co nejvíce od panáčka. Pro posunutí kamenu je použita funkce posunpost, takže není možné kámen posunout na zeď. kra_provaz.c 226: void posun (int pocet, kq_word **slova) 227: { 228: int xx, yy; 229: 230: if(!panacek){ 231: popup_info("nemuzes nic"); 232: return; 233: } 234: if(!kamen || (pocet && slova[0] != kaminek->slovo)){ 235: popup_info("neni duvod"); 236: return; 237: } 238: if(smpixel(kamen->submap, panacek->x, panacek->y) != dosahpredmet){ 239: popup_info("_too far"); 240: return; 241: } 242: 243: xx = kamen->x - panacek->x; 244: yy = kamen->y - panacek->y; 245: 246: if(abs(xx) > abs(yy)){ 247: if(xx > 0){ 248: xx = 5; 249: panacek->smer = VPRAVO; 250: } 251: else{ 252: xx = -5; 253: panacek->smer = VLEVO; 254: } 255: yy = 0; 256: } 257: else{ 258: xx = 0; 259: if(yy > 0){ 260: yy = 5; 261: panacek->smer = DOLU; 262: } 263: else{ 264: yy = -5; 265: panacek->smer = NAHORU; 266: } 267: } 268: 269: zmenapost(panacek); 270: if(posunpost(kamen, kamen->x+xx, kamen->y+yy)) popup_info("posunul kamen"); 271: else popup_info("posun do zdi"); 272: }
kq_postava *kamen: 224, 238–241, 244–245
void posun(): 24, 48, 110–112, 122–123, 206, 240–241
241
45 Modul kra predm
Program kraluk
45 Modul kra predm V tomto modulu se nalézá funkce vytvorpredmety, která založí všechny předměty ve hře. To jsou předměty, které mohou být v inventáři, tedy: kybl, pernicek, brneni, kokos, mkozisek (myší kožíšek), hvezdicka, odsmolicka (kolečko, které dostane od Smolíčka), kaminek, truhlicka, slanka, kytka, svicka a sluchatko. Dále je zde předmět princezna, který je jako předmět využíván pouze v podzemí, ačkoliv jeho slovo je použito pro další osoby (bohdanka, maruska, lada). Nakonec tu je předmět zebrik, který by se do inventáře neměl vůbec dostat, čímž spoléhám na správný soubor definující input, který by větu „seber zebříkÿ neměl pochopit. Tento předmět se vyskytuje ne políčku skala3. kra_predm.c 3: void vytvorpredmety () 4: { 5: kybl = vytvorpredmet("kybl", 1); 6: predmetpol(kybl, pol[5][5], 7: 158, 46, 58, 8: 71, 44, 10); 9: pernicek = vytvorpredmet("pernicek", 1); 10: predmetpol(pernicek, pol[1][1], 11: 68, 55, 53.2, 12: 26, 87, 10); 13: brneni = vytvorpredmet("brneni", 1); 14: zebrik = vytvorpredmet("srolzebr", 1); 15: predmetpol(zebrik, skala3, 16: 162, 96, 105, 17: 75, 98, 5); 18: kokos = vytvorpredmet("kokos", 1); 19: predmetpol(kokos, pol[4][5], 20: 50, -7, 110, 21: 23, 104, 5); 22: mkozisek = vytvorpredmet("mkozisek", 1); 23: hvezdicka = vytvorpredmet("hvezdicka", 1); 24: princezna = vytvorpredmet("princezna", 1); 25: predmetpol(princezna, lvi, 26: 39, 12, 0, 27: 13, 8, 5); 28: odsmolicka = vytvorpredmet("odsmolicka", 1); 29: kaminek = vytvorpredmet("kaminek", 1); 30: truhlicka = vytvorpredmet("truhlicka", 1); 31: predmetpol(truhlicka, vdrevchal, 32: 83, 26, 60.2, 33: 25, 49, 0); 34: slanka = vytvorpredmet("slanka", 1); 35: predmetpol(slanka, vdrevchal, 36: 103, 27, 60.2, 37: 48, 49, 0); 38: kytka = vytvorpredmet("kyticka", 1); 39: svicka = vytvorpredmet("svicka", 1); 40: sluchatko = vytvorpredmet("sluchatko", 1); 41: predmetpol(sluchatko, pol[0][0], 42: 87, 50, 0, 43: 36, 45, 5); 44: }
void vytvorpredmety(): 190, 205, 242 kq_predmet *kybl: 211–212, 242, 244 kq_predmet *pernicek: 210, 214, 216, 242, 244 kq_predmet *brneni: 208–211, 216, 218, 223, 242, 244 kq_predmet *kokos: 207, 222, 242, 244 kq_predmet *mkozisek: 207, 210–211, 214, 242, 244 kq_predmet *hvezdicka: 214, 221, 242, 244 kq_predmet *odsmolicka: 213–214, 242, 244 kq_predmet *kaminek: 215, 224, 237, 240–242, 244 kq_predmet *truhlicka: 242, 244 kq_predmet *slanka: 215, 242, 244 kq_predmet *kytka: 215, 242, 244 kq_predmet *svicka: 215–216, 224, 242, 244 kq_predmet *sluchatko: 213–214, 216, 242, 244 kq_predmet *princezna: 212, 216, 226–227, 237, 239–240, 242, 244 kq_predmet *zebrik: 204–205, 208–209, 215, 223, 242, 244
242
46 Modul kra animpost
Program kraluk
46 Modul kra animpost Tento modul obsahuje funkci nactianipy, která při startu programu načte animace některých postav, které na konci funkce zafixuje funkcí fix_anips. kra_animpost.c 3: void nactianipy () 4: { 5: chozeni = nactianip( 9, 40, "panac", 8, 0, 0, 0, 0); 6: brnanip = nactianip( 9, 40, "brneni", 8, 0, 0, 0, 0); 7: vevode1 = nactianip( 9, 36, "vevode1", 8, 0, 0, 0, 0); 8: vevode2 = nactianip( 9, 32, "vevode2", 8, 0, 0, 0, 0); 9: vevode3 = nactianip( 9, 24, "vevode3", 8, 0, 0, 0, 0); 10: plavani = nactianip(20, 14, "plave", 5, 0, 0, 1, 0); 11: topeni = nactianip(12, 15, "topi", 30, 5, 1, 1, 0); 12: padani = nactianip(16, 20, "pada", 8, 0, 1, 1, 0); 13: lezeni = nactianip( 9, 24, "leze", 10, 0, -1, 0, 0); 14: privazan = nactianip(11, 25, "privazan", 1, 0, 1, 0, 0); 15: 16: teleanip = nactianip(16, 70, "teleport", 15, 0, 1, 0, 0); 17: teleanip2 = nactianip(16, 70, "tele2", 15, 0, 1, 0, 0); 18: 19: jezianip = nactianip(12, 40, "jezibaba", 4, 0, 0, 0, 0); 20: jezileti = nactianip(13, 21, "jezileti", 1, 0, 0, 0, 0); 21: 22: fix_anips(); 23: }
Animace chozeni je naprosto běžný chodící panáček. V proměnné brnanip je panáček oblečený v brnění. V proměnných vevode1, vevode2, vevode3 a plavani jsou animace, které jsou nastaveny panáčkovi funkcemi brodi1, brodi2, brodi3, a plave pro různé zanoření panáčka do bezpečné vody. Animace topeni je použita pro topení se panáčka v nebezpečné vodě. Animace padani je použita, když panáček padá ze skály, žebříku nebo schodů (viz funkce skalopada). V proměnné lezeni je animace panáčka lezoucího po žebříku. Proměnná privazan zobrazuje panáčka, jak je přivázaný k provazu. V proměnných teleanip a teleanip2 jsou načteny animace obláčků, které teleportují panáčka. První bílý teleportuje panáčka na skálu, druhý žlutý ho teleportuje k jeskyni. Animace jezianip určuje chodící ježibabu a animace jezileti ježibabu na koštěti.
47 Modul kra prom Tento modul obsahuje pouze jednu funkci initprom, která nastaví proměnným při startu nebo restartu jejich počáteční hodnoty. Také nastaví pointery na NULL. kra_prom.c 3: void initprom () 4: { 5: dvere_tim = NULL; 6: most_sm = NULL; 7: telepost = NULL; 8: teletim = NULL; 9: jezibaba = NULL; 10: jezitimer = NULL; 11: jinapost = NULL; 12: pol_prichfunc = NULL; 13: krksedi = NULL; 14: krkleti = NULL; 15: odkrk = NULL; 16: jezilastpol = NULL;
void nactianipy(): 190, 243 kq_animpost *chozeni: 17, 190, 204, 210–211, 216, 219, 223, 238, 243 kq_animpost *brnanip: 209–211, 218, 223, 243 kq_animpost *vevode1: 211, 218, 243 kq_animpost *vevode2: 211, 218, 243 kq_animpost *vevode3: 211, 218, 243 kq_animpost *plavani: 218, 243 kq_animpost *topeni: 211, 219, 243 padani: 223, 239, 243 kq_animpost *lezeni: 209–210, 216, 223, 243 kq_animpost *privazan(): 243 kq_animpost *teleanip: 221, 243 kq_animpost *teleanip2: 221, 243 kq_animpost *jezianip: 204–205, 223, 230, 233, 243 kq_animpost *jezileti: 231–233, 243 void initprom(): 190, 243
243
48 Modul kra save 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: }
Program kraluk
kamen = NULL; wprovaz = NULL; peklohen = NULL; brnnastr = 1; nastrome = 0; makozisek = 0; dostalkyt = 0; dostalsvic = 0; smoldal = 0; jezil_x = jezil_y = 0; krkstav = 1; lvistav = 0; znak = 0;
48 Modul kra save Tento modul obsahuje pouze funkci registrujpf, co zaregistruje data programu pro moduly save a load. Ha, povedlo se mi tento modul popsat jako Hus (viz http://www.avas.cz/email-od-mistra-jana-husa.php). kra_save.c 3: void registrujpf () 4: { 5: add_sl_var(&dvere_tim, SL_TIMER); 6: add_sl_func(&men_dvere, SL_NULL); 7: 8: add_sl_var(&panacek, SL_POST); 9: add_sl_var(&dvere_post, SL_POST); 10: add_sl_var(&most_sm, SL_SUBMAP); 11: 12: add_sl_func(&teleportuj, SL_NULL); 13: add_sl_var(&telepost, SL_POST); 14: add_sl_var(&teletim, SL_TIMER); 15: 16: add_sl_var(&kybl, SL_PREDM); 17: add_sl_var(&pernicek, SL_PREDM); 18: add_sl_var(&brneni, SL_PREDM); 19: add_sl_var(&zebrik, SL_PREDM); 20: add_sl_var(&kokos, SL_PREDM); 21: add_sl_var(&mkozisek, SL_PREDM); 22: add_sl_var(&hvezdicka, SL_PREDM); 23: add_sl_var(&princezna, SL_PREDM); 24: add_sl_var(&odsmolicka, SL_PREDM); 25: add_sl_var(&kaminek, SL_PREDM); 26: add_sl_var(&truhlicka, SL_PREDM); 27: add_sl_var(&slanka, SL_PREDM); 28: add_sl_var(&kytka, SL_PREDM); 29: add_sl_var(&svicka, SL_PREDM); 30: add_sl_var(&sluchatko, SL_PREDM); 31: 32: add_sl_func(&kokpadstep, SL_NULL); 33: 34: add_sl_var(&brnnastr, SL_BOOL); 35: add_sl_var(&nastrome, SL_BOOL); 36: add_sl_var(&smoldal, SL_BOOL); 37: 38: add_sl_var(&jezibaba, SL_POST); 39: add_sl_var(&jezilastpol, SL_POL); 40: add_sl_var(&jezitimer, SL_TIMER); 41: add_sl_var(&pol_prichfunc, SL_FUNC); 42: add_sl_func(&jeziprichpol, SL_NULL); 43: add_sl_func(&continuejezi, SL_NULL); 44: add_sl_func(&jezichyt, SL_NULL); void registrujpf(): 190, 244
244
49 Restřík modulů 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: }
Program kraluk
add_sl_var(&jezil_x, SL_INT); add_sl_var(&jezil_y, SL_INT); add_sl_func(&houp_step, SL_WIDGET); add_sl_var(&makozisek, SL_CHAR); add_sl_var(&dostalkyt, SL_CHAR); add_sl_var(&dostalsvic, SL_CHAR); add_sl_var(&jinapost, SL_POST); add_sl_func(&objev_jp, SL_NULL); add_sl_func(&chyt_jp, SL_NULL); add_sl_func(&continue_jp, SL_NULL); add_sl_func(&pysna_random, SL_POST); add_sl_func(&null_jp, SL_POST); add_sl_func(&auto_jezin, SL_POST); add_sl_func(&jezin_chyt, SL_POST); add_sl_func(&jelen_step, SL_NULL); add_sl_var(&krkstav, SL_TRIT); add_sl_var(&krksedi, SL_ANIP); add_sl_var(&krkleti, SL_ANIP); add_sl_var(&odkrk, SL_ANIP); add_sl_func(&plasptaky, SL_NULL); add_sl_func(&krk_chyt, SL_POST); add_sl_var(&kamen, SL_POST); add_sl_var(&lvistav, SL_INT); add_sl_var(&wprovaz, SL_WIDGET); add_sl_func(&provaz_step, SL_POST); add_sl_var(&peklohen, SL_WIDGET); add_sl_func(&chyt_cert, SL_POST); add_sl_var(&znak, SL_CHAR);
C
Rejstříky
49 Restřík modulů 30. 21. 9. 18. 4. 25. 17. 29. 8. 27. 22. 11. 34. 37. 46. 39. 38. 42.
animwid . . . . . . . . . . automaticky animovaný obrázek na políčku . . . . . . . . . . . . . . . . . . . . . . . . 167 autopost . . . . . . . . . algoritmy pro automatické ovládání postavy . . . . . . . . . . . . . . . . . . . . . . . . 74 bindings . . . . . . . . . klávesové zkratky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 color . . . . . . . . . . . . co dělá která barva mapy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 defaults . . . . . . . . . výchozí hodnoty programu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 edit . . . . . . . . . . . . . spodní editační řádek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 filer . . . . . . . . . . . . čtení mapy z XPM souboru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 gsl . . . . . . . . . . . . . . grafický save a load . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 hash . . . . . . . . . . . . . vyhledávání ve slovníku . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 home . . . . . . . . . . . . . práce se soubory v domovském adresáři . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 input . . . . . . . . . . . . interpretace vstupních příkazů . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 keyboard . . . . . . . . . vstup z klávesnice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 kql . . . . . . . . . . . . . . načtení všech hlavičkových souborů . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 kra_polic . . . . . . . . inicializace políček (scén hry), funkce přechodů . . . . . . . . . . . . . . . . . . . . . 190 kra_animpost . . . . . animace postavy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 kra_barvy . . . . . . . . funkce reagující na barevnou mapu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 kra_input . . . . . . . . funkce reagující na příkazy uživatele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 kra_jezibaba . . . . . aktivity ježibaby . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229 245
50 Rejstřík funkcí, struktur a proměnných 41. 40. 43. 45. 47. 44. 48. 36. 24. 7. 28. 12. 19. 33. 6. 23. 5. 14. 31. 26. 20. 32. 28. 13. 2. 35. 3. 16. 15. 10.
Program kraluk
kra_jezin . . . . . . . . smolíček, jelen, jezinky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 kra_jp . . . . . . . . . . . všelijaké postavy hry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 kra_krk . . . . . . . . . . krkavci, Bohdanka . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 kra_predm . . . . . . . . načtení předmětů . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242 kra_prom . . . . . . . . . inicializace proměnných . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 kra_provaz . . . . . . . animace spouštění a vytahování po provazu . . . . . . . . . . . . . . . . . . . . . . . . 237 kra_save . . . . . . . . . registrace funkcí a proměnných pro ukládání pozic . . . . . . . . . . . . . . . . . . 244 kraluk . . . . . . . . . . . funkce main() a restart() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 languages . . . . . . . . přepínání jazyků . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 list . . . . . . . . . . . . . jednoduchý zásobník . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 load . . . . . . . . . . . . . restaurování stavu programu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 loop . . . . . . . . . . . . . hlavní smyčka programu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 map . . . . . . . . . . . . . . pole barev pro různé aktivity ve scéně . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 misc . . . . . . . . . . . . . init, start, restart, exit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 mystring . . . . . . . . . stringy neomezené délky a operace se stringy . . . . . . . . . . . . . . . . . . . . . . . 12 output . . . . . . . . . . . konverze z labeblíku na nápis pro výstup . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 pin . . . . . . . . . . . . . . deklarace typu kq_pin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 pixmap . . . . . . . . . . . čtení obrázků z XPM souborů, škálování . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 pol . . . . . . . . . . . . . . políčko neboli jedna scéna hry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 popup . . . . . . . . . . . . okno s výstupním textem nebo výběrem . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 post . . . . . . . . . . . . . struktura kq_postava (widget+submap+timer) . . . . . . . . . . . . . . . . . . . . . 63 predmet . . . . . . . . . . předměty, inventář . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 save . . . . . . . . . . . . . uložení stavu programu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 timer . . . . . . . . . . . . časovač programu (Xlib neimplementuje svůj časovač) . . . . . . . . . . . . . . . 27 types . . . . . . . . . . . . typedef některých struktur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 version . . . . . . . . . . definice aktuální verze . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 warning . . . . . . . . . . funkce pro varující a chybové hlášky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 widget . . . . . . . . . . . datová struktura elementu obrázku . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 window . . . . . . . . . . . členění okna programu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 X . . . . . . . . . . . . . . . . nízkoúrovňové funkce spolupracující s X . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
50 Rejstřík funkcí, struktur a proměnných Vedle každého hesla je tučně stránka, kde je heslo dokumentováno, a dále kurzívou je vytištěn seznam stránek, kde se heslo vyskytuje. Heslo tvaru cosi /*kdesi*/ značí, že indetifikátor cosi je lokální (static) uvnitř modulu kdesi. Před heslem je jeho typ (menším písmem a černě), který nepodléhá abecednímu řazení add_sent(): 87, 84, 88, 187, 205–206 add_sl_func(): 157, 158–159, 244–245 add_sl_var(): 156, 37, 155, 159, 244–245 kq_word *add_word(): 87, 86, 88, 182, 187, 205 void addbind(): 19, 20–21 void addgbind(): 20 void addIdoL(): 15, 92 void addPdoL(): 15, 81, 88, 93–94, 103 DIR adresar /*gsl*/ : 165, 166 int aktuFPS: 26, 27, 160–162 int aktuhist: 114, 110, 112, 115–118, 163, 165 kq_word *aktulang: 103, 104–108, 161–162, 187 kq_word *aktulslovo: 88, 87, 89, 91, 188 kq_policko *aktupol: 170, 137, 139, 143, 169, 171–173, 175–179, 181–182, 184, 188, 206, 209–216, void
void void
223–227, 230, 233, 238 aktuselect: 123, 124–126, 163–164 kq_timer aktutimer: 28, 29–33, 139–140, 168, 222, 226–227, 229, 234, 236, 238–239 kq_anim *animpole: 179, 137, 139, 143, 147, 180–181 int ANIMPRIOR: 71, 11, 73 void animuj(): 167, 137, 159 void anip_step(): 71, 70, 73, 159, 209, 238 char *ANIPDIR: 10, 72 char *ANIPSTR: 10, 72 void apply_load(): 146, 149, 156, 160 void apply_loaded_hist(): 118, 161–162 void auto_clever(): 79, 159, 204, 215, 226, 230 void auto_jezin(): 228, 245 void auto_random(): 75, 159, 204, 225 void autopost(): 65, 204, 214–215, 226, int
246
50 Rejstřík funkcí, struktur a proměnných
Program kraluk
228, 230, 232–233, 235–236 daruj: 214, 205 AUTOPRIOR: 65, 11 char *DATADIR: 9, 10, 33–34, 54, autoreloadmap: 58, 57, 61–62, 89, 101, 104, 187 147, 171–173, 188 char *DATADIR_LOCAL: 9, 187 AUTOU_POST: 64, 153 int DEF_POP_SIRKA: 10, 11, 21, 99–100, AUTOU_SOUR: 64, 142, 152, 226 107–108, 163, 184–186 void bachakytky(): 220, 192 int DEF_POP_VYSKA: 10, 11, 21, 99–100, void barvapolic(): 224, 217 107–108, 163, 184–186 kq_submap bg_map: 56 int DEF_POP_X: 10, 11, 21, 99–100, char *BGDIR: 9, 39, 42 107–108, 163, 184–186 BINDTEXT: 17, 18–21 int DEF_POP_Y: 10, 11, 21, 99–100, BINDWIN: 17, 18–20 107–108, 163, 184–186 kq_word *bobes: 212, 195, 205, 213 char delete(): 111, 20–21, 164 kq_word *bohdanka: 212, 205, 213, 237, 242 void deleteAanips(): 74, 148, 188 char bpos /*load*/ : 129, 130 void deleteApixmaps(): 37, 147, 188 char bpos /*save*/ : 128 void deleteAposts(): 68, 148, 188 kq_color *breh: 219, 217, 220 void deleteApredmets(): 186, 148, 188 kq_animpost *brnanip: 243, 209–211, 218, 223 void deleteAsubmaps(): 62, 147, 188 kq_predmet *brneni: 242, 208–211, 216, 218, 223, 244 void deleteAtimers(): 32, 27, 148, 188 void brodi1(): 218, 217, 243 void deleteAwidgets(): 50, 147, 188 void brodi2(): 218, 217, 243 void deletelanips(): 73, 173 void brodi3(): 218, 217, 243 void deletelpixmaps(): 36, 173 char byte /*load*/ : 129, 130 void deletelposts(): 66, 173 unsigned char byte /*save*/ : 128 void deletelsubmaps(): 61, 173 char cekalose: 25, 24, 26, 34, 119, 123, 165 void deleteltimers(): 31, 27, 173 kq_word *certi: 212, 203, 205, 213 void deletelwidgets(): 49, 173 void check_cs(): 130, 144, 160, 162 int delka /*edit*/ : 108, 109–112, void check_idstr(): 134, 135, 160 114–118 kq_animpost *chozeni: 243, 17, 190, 204, 210–211, int delkaL(): 15, 16, 95–96 216, 219, 223, 238 unsigned int depth: 22, 35 char chyba /*load*/ : 128, 129–130, 135, int dfv /*input*/ : 88, 89, 96 144–146, 150–157, 159–162 Display *display: 22, 23, 25, 34–37, 40–46, char chyba /*save*/ : 127, 128, 131, 135, 48–50, 109–111, 119–123, 139–141, 156–157, 159–160 125–126, 147, 163, 186, 188–189 chyt_cert(): 204, 245 int display_sirka: 22, 39, 43 void chyt_jp(): 226, 225, 245 int display_vyska: 22, 39, 43 kq_word *divka: 212, 205, 213, 216, Cislo: 136, 27, 35, 37, 44, 56, 63, 70, 74, 86–88, 137–139, 168, 170–171, 181 226–227, 237–238 void clearselect(): 126, 163–164 char dobind(): 19, 25, 120 void cleartext(): 109, 110, 112–113, void dohistory(): 116, 115 116–117, 165 DOLU: 9, 20–21, 69–72, 169, 172, 190, void continue_jp(): 226, 245 199–204, 209, 216, 220–221, void continuejezi(): 230, 231–232, 235, 244 228–229, 231–232, 235, 240–241 void createpwin(): 121, 119, 123 void domu(): 216, 206 char *cs1 /*load*/ : 130, 129 kq_color *dosahpredmet: 185, 207–211, char *cs1 /*save*/ : 130, 128, 131 213–215, 217, 240–241 int cs1pos /*load*/ : 130, 129 char dostalkyt: 226, 215, 225, 244–245 int cs1pos /*save*/ : 130, 128, 131 char dostalsvic: 226, 215, 225, 244–245 char *cs2 /*load*/ : 130, 129 int DOT: 109, 10 char *cs2 /*save*/ : 130, 128, 131 void dotimers(): 30, 24, 27–28 int cs2pos /*load*/ : 130, 129 void dovody /*kra_barvy*/ (): 218, int cs2pos /*save*/ : 130, 128, 131 219–220 char *DOWNSTR: 10, 72 CSL: 130, 128–129, 131 void drawpopup(): 122, 120, 123, 165 void ctiradky /*input*/ (): 89, 90, 95 void drawselect(): 125, 122, 126, 163–164 void ctiznak /*input*/ (): 90 void dupnstr(): 13, 92–94, 117 char cyklhist /*edit*/ : 114, 115, 118 int char
247
50 Rejstřík funkcí, struktur a proměnných 14, 18, 36, 57, 81, 91, 93, 107, 119, 175–177, 182 kq_word *dvere: 206, 192–193, 195, 205, 207–208, 232 kq_postava *dvere_post: 207, 194, 208, 244 kq_timer *dvere_tim: 207, 208, 243–244 void edithist(): 116, 110–111 char *editpole /*edit*/ : 108, 110, 112, 114–118 void error(): 8, 14, 22, 34, 51, 53, 109, 119 void expandvetu(): 82, 80, 92 struct fileinfo: 166, 165 char filtrovano /*gsl*/ : 167, 163 int filtruj /*gsl*/ (): 167, 163–164 void finishws(): 88, 188 void fix_anips(): 74, 243 void fix_pix(): 37, 74 kq_animpost *fixed_anips: 74, 152 kq_pixmap *fixed_pixmaps: 37, 150 void fixujokno /*window*/ (): 41, 40, 43 XFontStruct *font_info: 109, 40, 110–112, 116–117, 188 int font_y /*edit*/ : 109, 110–111 char *FONTNAME: 109, 10 double FPSs: 26, 27 void free_animpole(): 181, 147, 173 void free_loaded(): 148, 160 void freeanip(): 73 void freekqPixmap(): 36, 37, 73, 186 void freeoutputs /*languages*/ (): 106 void freesents /*languages*/ (): 107, 106 void freesm /*map*/ (): 57, 62 void freeword /*languages*/ (): 106 void fullscreen(): 43, 20, 39 char fullscreened: 38, 11, 39–40, 42–43, 161–162 int gargc: 8, 40, 187 char gargv: 8, 40–41, 187 int gelka /*edit*/ : 109, 110–113, 115–117 void getchytsour(): 64, 75, 79, 232 GC ggc: 22, 42, 49 void gload(): 165, 20 kq_color *globbarva: 168, 169–171 void grestart /*bindings*/ (): 21, 20 void gsave(): 165, 20 int gursor /*edit*/ : 109, 110–113, 115–117 void hash_add(): 18, 20, 93–94, 102, 105 kq_pin hash_find(): 19, 81, 93, 99, 102–103 int hashfunc(): 18, 19 HASHSIZE: 17, 18, 106 struct hash **hashtable: 17, 18–19, 106 void hidepost(): 65, 66, 70, 209, 221 void hidesubmap(): 61, 66, 69, 79, 173, 220 void hidewidget(): 44, 67 char *dupstr():
Program kraluk /*edit*/ : 114, 112, 115–116, 118 char *homedir: 127, 130, 160–161, 165–166, 188 FILE *homefopen(): 127, 129 int HOT: 109, 10, 110 void houp_step: 234, 245 void houpejzebr(): 234, 205 kq_predmet *hvezdicka: 242, 214, 221, 244 char *ICON_NAME: 10, 40–41 char *ident_str: 135, 134 IDIR: 9 int IMAGRAT: 34, 11, 35 char *IMGDIR: 9, 10, 33–34 char *IMGSUFFIX: 10, 33–34 char *INHOMEDIR: 10, 127 void init_sl(): 159, 187 void initbindings(): 20, 187 voidinithash(): 17, 187 void inithome(): 127, 187 void initklav(): 22, 23, 188 void initprom(): 243, 190 void initstr(): 12, 13, 90, 102, 104 void initX(): 22, 187 char *INPUTSUFFIX: 10, 89 void INTERCOLUMNSKIP: 124, 11, 125–126 int INTERLINESKIP: 124, 11, 120–122, 125–126 kq_predmet *inventar: 181, 142, 148, 182, 185–187 void jazslova /*languages*/ (): 105, 106 void jdipost(): 69, 63, 65, 67–68, 71, 159, 236, 238 JEDNA: 128, 129, 134 kq_word *jelen: 212, 193, 205, 213, 215, 229 void jelen_step(): 229, 245 struct veta *jenkat: 83, 82, 95, 97, 105–107 jezed /*autopost*/ (): 76, 77–80 JEZI_DOLET_X: 232, 233 JEZI_DOLET_Y: 232, 233 JEZI_START_X: 229, 230, 232–233 JEZI_START_Y: 229, 230, 232–233 kq_animpost *jezianip: 243, 204–205, 223, 230, 233 kq_postava *jezibaba: 229, 204–205, 209, 223–224, 230–235, 243–244 void jezicekej(): 233, 209 void jezichyt(): 232, 230, 244 void jezichytej(): 234, 223, 230–231 int jezil_x: 232, 230–231, 233, 244–245 int jezil_y: 232, 230–231, 233, 244–245 kq_policko *jezilastpol: 230, 231–233, 243–244 kq_animpost *jezileti: 243, 231–233 void jezin_chyt(): 228, 245 kq_word *jezinky: 212, 192, 205, 213 void jezinsmer /*kra_jezin*/ (): 228 void jezinull(): 233, 223, 234–235 void jeziprichpol(): 230, 231, 244 char **history
248
50 Rejstřík funkcí, struktur a proměnných
Program kraluk
172–173, 175–176, 181, jezishor(): 234, 223, 230–231 203–204, 215, 218–225, 227–228, 212, 205, 213, 230–231, 234 232, 235–236, 238, 246 230, 231, 243–244 kq_predmet: 181, 7, 87, 138–139, jezivzdej: 234, 223–224, 235 142–143, 146, 148, 153–154, kq_postava *jinapost: 225, 213–215, 226–227, 168, 182–186, 190 229, 243, 245 kq_string: 12, 7, 13, 15, 90, 101, 104 char *joinstrings(): 14, 34, 39, 42, 54, kq_submap: 56, 7, 53, 57–63, 65, 72, 89, 101, 104, 107, 127, 132, 136–137, 139–140, 143, 130, 165–166, 188, 206 145–146, 148, 151, 174–175 kq_postava *kamen: 241, 224, 238–240, 244–245 kq_predmet *kaminek: 242, 215, 224, 237, 240–241, kq_timer: 27, 7, 28–33, 63, 65, 244 132, 136, 138–141, 143, int katnumber /*input*/ : 92, 93 145–146, 148, 154, 167 KEY_BACKSPACE: 9, 164 kq_widget: 44, 7, 45–51, 63, 65, KEY_DELETE: 9, 164 132, 136–137, 139–140, KEY_DOWN: 9, 123, 164 143–146, 148, 150, 167, 234 KEY_END: 9, 164 kq_word: 86, 7, 80–83, 87–88, 90, KEY_ENTER: 9, 119–120, 123, 164 98–99, 101, 103–108, 137, KEY_ESC: 9, 119–120, 123, 163 139, 146, 149, 161, 170–173, KEY_HOME: 9, 164 181–182, 185, 205–217, 240–241 KEY_LEFT: 9, 123, 164 void kql_defaults(): 9, 10–11, 187, 190 KEY_RIGHT: 9, 123, 164 void kql_exit(): 188, 20, 217 KEY_SPACE: 9, 119–120 void kql_init(): 187, 8, 12, 26, 159, 190 KEY_TAB: 9, 164 void kql_restart(): 188, 21, 214 KEY_UP: 9, 123, 164 void kql_square(): 173, 209, 216–217, struct keybind: 19 221, 224–225, 233, 238 kq_predmet *kokos: 242, 207, 222, 244 void kql_start(): 187, 188, 190 void kokpadstep(): 222, 244 kq_word *kral: 212, 9–10, 187, 190, void konec(): 217, 29, 90, 129, 164, 205 200, 205, 213–214 void koukniinv(): 186 kq_word *krasomila: 212, 205, 213, 226–227 kq_anim: 167, 7, 137, 143–144, 155, 179 void kreslianim(): 22, 24 kq_animpost: 70, 7, 63, 65, 71–74, void krk_chyt(): 236, 245 136, 138–139, 141, 143, kq_word *krkavci: 212, 193, 205, 213–214, 145, 148, 151–152, 203, 235–236 218, 222, 225, 227, 235 kq_animpost *krkleti: 235, 236, 243, 245 kq_color: 53, 7, 54–56, 60–61, 69, 137, kq_animpost *krksedi: 235, 236, 243, 245 168, 173, 185, 192, 196, 217–225 char krkstav: 235, 216, 236–237, 244–245 kq_filer: 51, 7, 52–54 int KURSIR: 110, 10, 111 kq_list: 15, 7, 16, 80–82, 88, 91–93, int kursor_vyska /*edit*/ : 109, 110 95, 101, 168, 170–173 kq_predmet *kybl: 242, 211–212, 244 kq_map: 54, 7, 51, 56 kq_predmet *kytka: 242, 215, 244 kq_output: 98, 7, 99, 101–103, 106 kq_word *lada: 212, 10, 19, 91, 114, 205, kq_pin: 11, 6–7, 12, 17–20, 27, 213, 226–227, 242 33, 81, 86, 93–94, 99, 101, char *LANGCAT: 10, 105 105, 158–159, 246 char *LANGDIR: 10, 89, 101, 104 kq_pixmap: 35, 7, 36–37, 39, 44–45, char *LANGFILE: 10, 104 48, 67, 70, 72, 74, 136–138, LANGWORD: 87, 103–104, 107 141, 143–144, 146, 148, int *LdoIA(): 16, 92 150, 152, 167, 180, 186 void **LdoPA(): 16, 80, 88, 94–95 kq_policko: 168, 7, 136, 138, 143, LEDO: 9, 20–21 154, 169–174, 176, 178, 181, char *LEFTSTR: 10, 72 183, 191, 200, 203–205, 225, LENA: 9, 20–21 227, 229, 231, 235, 237 kq_word *lev: 212, 9–10, 44, 47, 200, kq_postava: 63, 6–7, 53, 64–69, 71, 205, 213, 224, 238 73, 75–76, 79, 136, 138–139, void levchyt(): 224, 199 141, 143, 145, 148, 152–153, kq_animpost *lezeni: 243, 209–210, 216, 223 void
kq_word *jezislovo: kq_timer *jezitimer:
249
50 Rejstřík funkcí, struktur a proměnných
Program kraluk
/*load*/ : 143, 144, 146–147, 149, 155 kq_postava *loaded_posts /*load*/ : 143, 144–145, 148–149, 152–153 kq_policko *load_awid: 155, 157 kq_timer *loaded_predmets /*load*/ : 143, kq_policko *load_awids: 155, 160 144, 146, 148–149, 153–154 char load_bit(): 129, 130, 132–134, kq_submap *loaded_submaps /*load*/ : 143, 136, 150–154, 157, 162 144–145, 147, 149, 151 load_char(): 134, 135, 157, 162 kq_timer *loaded_timers /*load*/ : 143, void load_conf(): 161, 187 144, 146, 148–149, 154 void load_end(): 129, 160, 162 kq_widget *loaded_widgets /*load*/ : 143, float *load_float(): 136, 150–151, 153–154, 144–145, 147–148, 150–151 157 void loadfont(): 109, 39 void *load_func(): 159, 152, 154, 157 void loadpopupfont(): 119, 39 int load_int(): 133, 136, 149–154, 157, 159 void loop(): 24, 25, 28, 187–188 int load_intoddo(): 134, 150–155, 159, 162 intLOT: 113, 10, 109–110, 112, 116–117 void load_kontexts(): 149, 160 kq_word *lotrando: 212, 205, 213–214, 226–227 kq_pixmap *load_pixmap(): 150, 152, 155, 157 kq_policko *lvi: 191, 199, 213, 224, 237–239, 242 void load_pixmaps(): 150, 160 unsigned int lvistav: 237, 224, 238–239, 244–245 void load_pocty(): 143, 160 int main(): 190, 7–8, 246 void *load_pointer(): 157, 156, 159 void makozisek: 226, 214, 225, 244–245 kq_policko *load_pol(): 154, 144, 153, 157 int map_xa: 62, 67, 168, 171 kq_post *load_post(): 153, 157 int map_xb: 62, 67, 168, 171, 183 void load_posts(): 152, 160 int map_ya: 62, 67, 168, 171 kq_predmet *load_predmet(): 154, 157 int map_yb: 62, 67, 168, 171, 183 void load_predmets(): 153, 160 kq_map mapa: 56, 35–36, 58–60, 62–63, 69–70, void load_sminfo(): 151 77, 141, 152, 168–174, 179, 203, void load_start(): 128, 129, 160–161 218–219, 230–232, 239–240 char *load_string(): 135, 150–151, 153, 162 float *mapa_z: 56, 58–60, 62, 69–70, 77, kq_submap *load_submap(): 151, 152, 157 173–174 void load_submaps(): 151, 160 char *MAPDIR: 9, 54 kq_timer *load_timer(): 154, 152–153, 155, 157 kq_color *mappixel(): 54, 60, 69, 77, 173–174, void load_timers(): 154, 160 218–219, 230–232, 239–240 void load_tinfo(): 154 char *MAPSUFFIX: 10, 54 char load_trit(): 131, 132, 150–151, kq_word *maruska: 212, 205, 213, 226–227, 242 153–154, 157, 159 int maxFPS: 26, 27, 161–162 unsigned int load_unsint(): 132, 133, 135, 144, 151, 153–155, 161–162 MAXHISTORY: 114, 115, 118 void load_vars(): 156, 160 int MAXRATIO: 10, 11, 43 kq_widget *load_widget(): 150, 153, 155, 157 void men_dvere(): 207, 208, 244 void load_widgets(): 150, 160 char mengraf: 22, 25, 41–42, 45–46, 48–50, void load_winfo(): 150 66, 115, 120, 123, 147 kq_word *load_word(): 149, 153, 157 void menpost: 66, 65, 67, 148 kq_animpost *loaded_anips /*load*/ : 143, int mf_cislo(): 52, 54–55 144–145, 148–149, 151–152 void mf_error(): 53, 52, 55 kq_timer *loaded_apole /*load*/ : 143, void mf_musibyt(): 52, 54–55 144, 146–147, 149, 155 void mf_najdi(): 52, 54–55 kq_submap *loaded_bgmap /*load*/ : 143, kq_filer *mf_otevri: 51, 54 144, 147, 151 void mf_zavri(): 53, 55 kq_submap *loaded_hidmap /*load*/ : 143, int mf_znak(): 51, 52, 55 144–145, 147, 149, 151 int MINRATIO: 10, 11, 43 kq_widget *loaded_hidwids /*load*/ : 143, kq_predmet *mkozisek: 242, 207, 210–211, 214, 244 144–145, 147, 149–151 void mluv(): 212, 206, 213 kq_timer *loaded_pautims /*load*/ : 143, kq_submap *most_sm: 220, 194, 243–244 144, 146, 148–149, 154 kq_word muz: 212, 47, 195, 200, 205, 226–227 kq_pixmap *loaded_pixmaps /*load*/ : 143, void *mymalloc(): 8, 13–16, 18–19, 33, 144, 147–148, 150 35–36, 45, 51, 54, 56–57, 59, void
load_all(): 160, 165, 188
kq_timer *loaded_pol
kq_animpost *load_anip(): 152, 153, 157 void load_anips(): 151, 160
250
50 Rejstřík funkcí, struktur a proměnných 67, 72, 82–83, 88, 91, 94, 96–97, 100, 102–105, 108, 115, 156, 158, 163, 166, 169–171, 175–177, 179–180, 182, 185 kq_animpost *nactianip(): 71, 175–176, 184, 203, 214, 222, 224–225, 228–229, 235–236, 243 void nactianipy(): 243, 190 void nactigbarvy(): 217, 190 void nactiinput(): 88, 89, 105–106 int *nactikat /*input*/ (): 92, 91, 95 kq_pixmap *nactikqXPM(): 36, 72, 179, 186, 203, 205, 224, 228, 232, 234, 237–238 kq_map nactimapu(): 54, 57, 148 void nactioutput(): 101, 105–106 Pixmap nactiXPM(): 33, 34, 36, 39, 41–42, 147 NAHORU: 9, 20–21, 69–72, 169, 172, 199–202, 204, 207–208, 219–221, 224, 228–229, 231–232, 240–241 kq_submap *najdibarvu(): 60, 61, 209, 215 void nalej(): 211, 206 void nastavicon /*window*/ (): 41, 40 void nastavpolicka(): 191, 190 char nastrome: 208, 209–210, 216, 244 kq_color *nebvoda1: 219, 217–218 kq_color *nebvoda2: 219, 217–218 kq_color *nebvoda3: 219, 217–218 kq_color *nebvoda4: 219, 217–218 kq_submap *nejvyssipix(): 60 void newpol(): 170, 169, 191–197, 199–200 void normal_z(): 218, 190, 196, 204, 216, 219–221, 223–224, 226, 228–231, 235, 238 void null_jp(): 227, 225, 229, 245 void null_krk(): 236, 192 void nullosobu: 229, 192 void nullujznak: 200, 191 void nuluj_z(): 218, 196, 219 char obejdized /*autopost*/ (): 77, 79–80 void objev_jp(): 226, 245 OBJWORD: 87, 182, 185 void oblec(): 210, 206 int ocursor /*edit*/ : 115, 116, 118 void odch_bohd(): 237, 193 void odch_hrad(): 204, 200 void odch_most(): 220, 194 void odchzebr(): 204, 192, 199 int odelka /*edit*/ : 115, 116, 118 kq_animpost *odkrk: 236, 243, 245 void odoznacsel(): 125, 126, 164 kq_predmet *odsmolicka: 242, 213–214, 244 void odzaltext(): 116, 165 int ogelka /*edit*/ : 115, 116, 118 int ogursor /*edit*/ : 115, 116, 118 kq_color *ohen: 223, 211, 217, 230–232 void okoli(): 206, 126
Program kraluk OKRAJ: 38, 11, 39–44 okraj_to_text(): 41, 42–43, 110, 112–113, 163–165 void okraj_to_win(): 41, 112–113, 117, 163–165 char okrajtext: 41, 11, 19, 25, 40, 42–43, 109–110, 112, 115–116, 161–165 Window okrajwin: 39, 40–42, 161 int oposunuti /*edit*/ : 115, 116, 118 void opravschody(): 203, 199 void opravvodu(): 200, 191, 193–196 kq_word *osoba: 212, 195, 200, 203, 205, 213, 216, 226–231, 234, 237–238 void otevri: 207, 51, 89, 101, 104, 205 void otevridvere /*kra_jezibaba*/ (): 232, 230, 233 OTHERHASH: 17 OUTPUT: 17, 19, 99, 102, 106 char *outputstring(): 98, 21, 99–100, 107–108, 165, 186 char *OUTPUTSUFFIX: 10, 101 kq_postava *ovlpost: 21, 22, 159, 185, 190, 204, 211, 215–217, 219, 221–224, 232, 238 void oznacsel(): 125, 126, 164 padani: 243, 223, 239 void paddovody(): 219, 217 void padejkokos(): 222, 196 kq_postav *panacek: 190, 204, 206–219, 221–226, 228, 230–232, 234, 236–241, 244 void pausetimer(): 31, 27, 66, 226 kq_policko *peklbrana: 191, 199, 224 kq_policko *peklo: 191, 199, 203, 212, 224 widget *peklohen(): 203, 212, 244–245 kq_predmet *pernicek: 242, 210, 214, 216, 244 XFontStruct *pfont /*popup*/ : 119, 120–122, 124–126 int pfv /*input*/ : 88, 89, 96–97 GC pgc /*popup*/ : 121, 120, 122–123, 125 PININT: 11, 12, 93, 158–159 kq_pin pinint(): 11, 12, 20–21, 93, 105, 207–208 PINNULL: 11, 12, 158–159, 187 kq_pin pinnull: 12, 20–21, 87–88, 94, 187, 221–222, 226, 229–232, 235 PINPOINTER: 11, 19, 81, 99, 102, 159, 185 kq_pin pinpointer(): 11, 12, 20, 65, 68, 73, 94, 102, 104, 167, 182, 224, 226, 233–234, 236, 239 PIX_SIR: 36, 39, 42–43, 46, 49, 147, 186 PIX_VYS: 36, 39, 42–43, 46, 49, 147, 186 void plasptaky(): 236, 235, 245 kq_animpost *plavani: 243, 218 void plave(): 218, 192, 243 int pocet_anip /*load*/ : 143, 144–145, 152 int pocet_anip /*save*/ : 138, 139 int
void
251
50 Rejstřík funkcí, struktur a proměnných
Program kraluk
pocet_fixanips: 74 char popupoutput(): 99, 184–186, 213–214 pocet_fixpix: 37, 136–137, 150 char *POPUPSMALLFONT: 119, 10 pocet_hsm /*load*/ : 143, 144–145, char popupstring(): 119, 21, 99–100, 107, 151 120 int pocet_hsm /*save*/ : 138, 137, 139 void popupwarning(): 99, 83, 100, 184, int pocet_hwid /*load*/ : 143, 144–145, 214–215 151 char **popvyber /*popup*/ : 123, 124–125 int pocet_hwid /*save*/ : 138, 137, 139 int porovnej /*gsl*/ (): 166 int pocet_pix /*load*/ : 143, 144, 150 kq_widget *poshidwid: 44, 45–47, 49–51, int pocet_pix /*save*/ : 138, 137, 139 139–140, 143, 147 int pocet_pol: 170, 136, 138, 155, 171 int poslhist /*edit*/ : 114, 112, 115, 118 int pocet_post /*load*/ : 143, 144–145, int poslkat /*input*/ : 92, 89, 93 153 pol_widget *pospw /*pol*/ : 177, 169, 171, 178–179 int pocet_post /*save*/ : 138, 139 void post_submap(): 63, 64, 175–176, int pocet_ptim /*load*/ : 143, 184, 224, 226, 229 144, 146, 154 void post_vzdal(): 76, 226, 236 int pocet_ptim /*save*/ : 138, 139 void post_z(): 65, 68, 176, 209, 218, int pocet_sm /*load*/ : 143, 144–145, 151 220, 224, 230–233, 235 int pocet_sm /*save*/ : 138, 137, 139 void posun(): 241, 24, 48, 110–112, int pocet_tim /*load*/ : 143, 144–145, 122–123, 206, 240 154 void posunkursor(): 111, 21, 115, 164 int pocet_tim /*save*/ : 138, 139 void posunpost(): 68, 69–70, 173, 221–222, int pocet_wid /*load*/ : 143, 144, 151 228, 232, 237, 239–241 int pocet_wid /*save*/ : 138, 137, 139 void posunselect(): 126, 123, 164 kq_word *pocet_word: 88, 87, 89, 91, 137, 150 char posuntext(): 113, 43, 109–112, 116–117 kq_policko **pol: 190, 191–196, 199–202, 204–205, int posunuti /*edit*/ : 113, 207–211, 214–216, 218, 109, 112, 115–117 220–221, 223–227, 229, int posunuti /*popup*/ : 124, 232–233, 237–239, 242 122–123, 125–126 void *pol_odchfunc(): 169, 173, 191, 200 void posunwidget: 48, 234, 238–239 pol_postava: 175, 8, 168, 170, 173, 176 void posunzwidghet: 48 void pol_postavy /*pol*/ (): 176, 171–172 int POT: 113, 10, 109, 111 void *pol_prichfunc(): 169, 173, 209, void pouzijmapu /*map*/ (): 59 230, 233, 243–244 pozadi: 39, 40, 42–43 pol_submap: 174, 8, 168, 170, 173, 175 int pps /*input*/ : 88, 89, 91 void pol_submapy /*pol*/ (): 175, 171–172 PRADO: 9, 20–21 pol_widget: 176, 8, 168–170, 177–180 PRANA: 9, 20–21 void pol_widgety /*pol*/ (): 179, 171–172 void prebarviwidget(): 48, 67, 167 char polvedle(): 172, 70 char **prectidir(): 165, 163 int POPDOT: 121, 10, 120, 122, 124–126 void predmetinv(): 183, 185, 207, 213–216 int POPHOT: 121, 10–11, 120, 122, 124–126 void predmetnull(): 183, 210, 214–215, int POPLOT: 121, 11, 120, 122, 124–126 218, 221, 223–224 int POPPOT: 121, 11, 120, 124 void predmetpol(): 183, 182, 215, 242 int POPRAMOKR: 121, 10, 120, 122, 124–126 void predTV(): 225, 200 int POPRAMSIR: 121, 10, 120, 122, 124–126 void prepnilang /*languages*/ (): 107, XFontStruct *popup_big_font: 119, 188 105 void popup_help /*bindings*/ (): 21, 20 void prepniokraj(): 113, 20 char popup_info(): 99, 21, 25, 84, 107, 185, void prestackujd /*widget*/ (): 47, 46, 48 188, 204, 206–216, 218, 220–226, void prestackujn /*widget*/ (): 228, 230–232, 234, 236, 238–241 47, 45–46, 48, 50 int popup_select(): 122 void prich_bohd(): 237, 193 void popup_selpocet(): 126, 163–164 void prich_jelen(): 229, 193 void popup_sl(): 163, 24, 165 void prich_jezin(): 227, 192 XFontStruct *popup_small_font: 119, 188 void prich_krk(): 235, 192 char * POPUPBIGFONT: 119, 10 void prich_most(): 220, 194 int POPUPBIGWIDTH: 119, 10 void prichpeklo(): 203 int int int
252
50 Rejstřík funkcí, struktur a proměnných prichzebr(): 205, 192, 199 pridej_pp(): 175, 176, 194 pridej_ps(): 170, 192–196, 200 void pridej_psm(): 175, 194 void pridej_pw(): 178, 191–197, 199–200 kq_color *pridejbarvu(): 54, 168, 192, 194, 196, 199–200, 217 void primosmer(): 75, 80, 228 kq_predmet *princezna: 242, 212, 216, 226–227, 237, 239–240, 244 char pripisznak(): 110, 25, 120, 164 void privaz(): 240, 206 kq_animpost *privazan(): 243 void prohodwid /*widget*/ (): 47 void promenujkrk(): 236, 214 void provazstep(): 237 void provedstr(): 80, 112 void provedvetu(): 82, 80, 83 void prozkoumej(): 206, 205 kq_color *prvbarva: 54, 55, 137, 168–171, 188 kq_submap *prvhidsm: 61, 57–58, 62, 139–140, 143, 147–148 kq_word *prvlang: 103, 104–105, 108, 162, 187 void prvnipol(): 172, 188 kq_pixmap *prvpix: 36, 37, 139, 141, 143, 147, 178–180 kq_policko * prvpol: 170, 155, 171 kq_postava *prvpost: 63, 66–68, 139, 141, 143, 148, 204, 212, 234, 236 kq_predmet *prvpredmet: 181, 139, 142–143, 148, 183, 187 kq_submap *prvsubmap: 58, 56–57, 59–62, 139–140, 143, 147–148, 222, 234 kq_word *prvulslovo: 88, 87, 89, 103, 139, 147, 149–150, 188 kq_widget *prvwidget: 44, 46–51, 139–140, 143, 147, 233–234 void prycodzdi /*kra_provaz*/ (): 239, 238 char *pstr /*popup*/ : 123, 119–122, 124–126 void pw_alloc /*pol*/ (): 177, 178–179 PW_ANIM: 178, 169, 177, 179 void pw_anim(): 178, 197–199 void pw_pix(): 177, 178, 197 void pw_wid(): 177, 178 void pw_xy(): 178, 192–194, 196–197 Window pwin /*popup*/ : 121, 120, 122–123, 125–126 void pysna_random(): 227, 225, 245 void randomsmer(): 74, 75 int ratio: 33, 11, 20, 34–36, 38–39, 41–44, 46, 48–49, 147, 161–162, 186–187 Window real_win /*window*/ : 39, 40–44 int real_win_sirka /*window*/ : 39, 40–43 void void void
Program kraluk real_win_vyska /*window*/ : 39, 40–43 void redrawtext(): 109, 25, 113, 116–117, 120, 123, 165 void registrujpf(): 244, 190 void reloadmap(): 58, 57, 62, 148, 171–172, 187, 234 void rescalePixmap(): 34, 39, 46, 48, 147 void restart(): 190, 7, 21, 246 void *restart_func: 188 char *RIGHTSTR: 10, 72 Window root: 22, 35, 40 float rozdilz /*pol*/ (): 178, 169, 171 kq_list *rozeberstr(): 81, 80, 92, 95 void save_all(): 160, 165, 188 void save_anip(): 138, 142, 152, 155, 157 void save_anips(): 141, 151, 160 void save_awid(): 137, 155, 157 void save_awids(): 143, 155, 160 void save_bit(): 128, 130–134, 136, 140–142, 155–156, 161 void save_char(): 134, 118, 135, 155–156 void save_color(): 137, 155, 157 void save_conf(): 161, 188 void save_cs /*save*/ (): 131, 130, 139, 160 void save_end(): 128, 160–161 void save_float(): 136, 140, 142, 155–156 void save_func(): 158, 140, 142, 156–157, 159 void save_hist(): 117, 161 void save_idstr(): 135, 160 void save_int(): 133, 136, 139–142, 155–156, 158 void save_intoddo: 133, 134, 136–138, 143, 158, 161 void save_kontexts(): 139, 149, 160 void save_pixmap(): 137, 140–141, 143, 150, 155, 157 void save_pixmaps(): 141, 150, 160 void save_pocty: 138, 136, 140, 160 void save_pointer(): 157, 156, 158 void save_pol(): 138, 139, 142, 154–155, 157 void save_post(): 138, 142, 153, 155, 157 void save_posts(): 141, 152, 160 void save_predmet(): 138, 153, 155, 157 void save_predmets(): 142, 153, 160 void save_sminfo(): 140, 151 void save_start(): 127, 160–161 void save_string(): 135, 140–142, 161 void save_submap(): 137, 140, 142, 151, 155, 157 void save_submaps(): 140, 151, 160 void save_timer(): 138, 141–143, 154–155, 157 void save_timers(): 140, 141, 154, 160 int
253
50 Rejstřík funkcí, struktur a proměnných save_tinfo(): 140, 141, 154 save_trit(): 131, 132, 140–142, 155–156, 158 void save_unsint(): 132, 118, 133, 135, 137–143, 161 void save_vars(): 156, 160 void save_widget(): 137, 142–143, 150, 155, 157 void save_widgets(): 140, 150, 160 void save_winfo(): 139, 140, 150 void save_word(): 137, 142, 149, 155, 157 char *SAVECONF: 10, 161 char *SAVELAST: 10, 188 char *SAVESUFFIX: 10, 165–166 kq_policko *schody1: 191, 199, 223 kq_policko *schody2: 191, 199, 223–224 int screen: 22, 40, 46, 121, 125, 147, 186 void seber(): 215, 25, 205 char seberpredmet(): 184, 185 char seberslovo(): 185, 215–216 void sebralspredmet(): 184, 185, 216 int SELECTOKR: 125, 11, 126 int selpocet /*popup*/ : 124, 126 int selsirka /*popup*/ : 124, 126 int selvyska /*popup*/ : 124, 122, 125–126 void set_pol(): 171, 147, 173, 187, 190 void setchytpost(): 64, 204, 225, 228, 234 void setchytsour(): 64, 67, 204, 215, 233, 235–236 void setdelay(): 25, 26–27 void setFPSs(): 26, 187, 190 char **seznamslov /*input*/ (): 93, 91, 94 void shor(): 223, 211, 217, 234 int sirka /*popup*/ : 121, 119–120, 122–124 kq_policko *skal_zebr1: 191, 199, 204–205, 223, 230–231, 234 kq_policko *skal_zebr2: 191, 199, 204–205, 209, 230–231 kq_policko *skala1: 191, 196, 199, 221, 231 kq_policko *skala2: 191, 197, 199, 230–231 kq_policko *skala3: 191, 197, 199, 209, 215, 230–231, 242 kq_color *skalopad1: 223, 217 kq_color *skalopad2: 223, 217 kq_color *skalopad3: 223, 217, 234 void skalopada(): 222, 217, 223, 234, 243 SL_ANIP: 155, 157, 245 SL_AWID: 155, 157, 159 SL_BOOL: 155, 156–157, 244 SL_CHAR: 155, 146, 156–157, 245 SL_COLOR: 155, 156–159 SL_FLOAT: 155, 147, 156–157 SL_FUNC: 156, 157–159, 244 struct sl_func: 158, 7, 159 void void
Program kraluk SL_INT: 155, 146, 156–157, 245 SL_NULL: 155, 244–245 SL_PIXMAP: 155, 157 SL_POL: 155, 157, 244 SL_POST: 155, 157, 159, 244–245 SL_PREDM: 155, 157, 244 SL_SUBMAP: 155, 157, 244 SL_TIMER: 155, 157, 244 SL_TRIT: 155, 156–157, 245 struct sl_var: 156, 7, 146 SL_WIDGET: 155, 157, 245 SL_WORD: 155, 157 kq_predmet *slanka: 242, 215, 244 void slez(): 209, 206 int sloupec /*popup*/ : 124, 125–126 struct slovo: 80, 82–83, 90–91, 94–95, 103, 105–106 kq_predmet *sluchatko: 242, 213–214, 216, 244 void smazkursor(): 110, 112–113, 117, 164 void smazlist(): 16, 80–81, 88, 92, 94–95, 102, 107 void smazstr(): 13, 90, 102, 104 kq_word *smolicek: 212, 192, 205, 213, 215, 227–228 kq_color *smpixel(): 60, 61, 185, 213–214, 220, 238, 240–241 void snez(): 210, 206 FILE *soubor /*load*/ : 128, 129–130, 160–161 FILE *soubor /*save*/ : 127, 128 float spocti_z(): 65, 67, 71 int spoctifr /*window*/ (): 43, 39, 42 void spoctivyber /*popup*/ : 124, 123 void spojpol(): 168, 169, 196 void spustfb(): 53, 63, 68–69, 174 void spustsparem(): 12, 19, 30 void spustzebr(): 215, 206 void start_jp(): 225, 192–193, 196 void startanimwid(): 167, 180 void startjezi(): 229, 216, 230 void startlang(): 105, 188 char *startsent: 88, 89 char *startword: 88, 89 STDWORD: 87, 88 STRDELKA: 12, 13 int STRKAL: 113, 10 int STRKAP: 113, 10 kq_word *strom: 208, 192–196, 205, 209 void sucho(): 219, 192, 218 kq_predmet *svicka: 242, 215–216, 224, 244 void svlec(): 211, 206 kq_animpost *teleanip: 243, 221 kq_animpost *teleanip2: 243, 221 void teleportuj(): 221, 244 kq_postav telepost: 221, 216–217, 222, 243–244 kq_timer *teletim(): 221, 217, 222, 243–244
254
50 Rejstřík funkcí, struktur a proměnných text_enter(): 112, 20 109–111, 189 109–112, 114–118, 163–165 int text_sirka: 39, 40, 43, 109, 111, 113 int text_vyska: 39, 40, 42–43, 109, 111 char *textcstr(): 117, 164 Window textwin: 38, 23, 39–41, 43, 109–111, 113, 120, 123, 163, 165 kq_animpost *topeni: 243, 211, 219 void topise(): 219, 217–218 kq_word tresne: 210, 192, 205 kq_predmet *truhlicka: 242, 244 kq_word *tus /*input*/ : 92, 90–91 void udalosti /*loop*/ (): 25, 24 float UINVPOMER: 186, 11 float UINVSIRKA: 186, 11 void ukazinv(): 185, 20 void ukazjaz(): 217, 205 void ukazkursor(): 110, 109, 111–113, 116, 164 void ukazwidgety(): 45, 171–172 void uklid /*hash*/ (): 18, 17 void ulozhist(): 114, 112 void ulozslova /*input*/ (): 90, 89, 93 void ulozvetu /*input*/ (): 95, 89 int unfullratio: 44, 11, 39, 43, 161–162 void unhidepost(): 65, 66, 209, 216, 222, 226, 230–232 void unhidesubmap(): 61, 66, 69, 79–80, 174, 220, 238 void unhidewidget(): 45, 67 void unpausetimer(): 31, 27, 66, 227 void updateposts(): 66, 24–25, 67, 121 void upravstring(): 14, 81, 86, 91–92, 103–104 char *UPSTR: 10, 72 uvnitrmapy /*autopost*/ (): 76, 77–78 int uvter /*loop*/ : 25, 24, 26 void uzmaspredmet: 184, 185, 216 kq_policko *vdrevchal: 191, 199, 216, 224, 242 void velikokno(): 42 VERSION: 189, 190 struct veta: 82, 80, 83, 95–96, 105, 107 struct vetnyclen: 82, 95–96, 105 void vetyslova(): 205, 190 kq_animpost *vevode1: 243, 211, 218 kq_animpost *vevode2: 243, 211, 218 kq_animpost *vevode3: 243, 211, 218 VLEVO: 9, 20–21, 69–72, 169, 172, 199–200, 220, 228, 230, 232, 240–241 kq_word *voda: 211, 192–196, 205, 212, 220 VPRAVO: 9, 20–21, 69–72, 168–169, 172, 199–200, 220, 225, void
GC text_gc: 22, 40, char *text_pole: 108,
Program kraluk 228, 232, 238, 240–241 vter /*loop*/ : 25, 24, 26 vyberpfont /*popup*/ (): 119, 123 void vykreslipol(): 171, 173, 188 void vylej(): 212, 206 void vylez(): 208, 205 kq_pixmap *vylovpix /*pol*/ (): 180 void vypistimer(): 33, 27 void vypistimery(): 33, 27 void vypiswidget(): 50, 51 void vypiswidgety(): 50, 51 void vyradpredmet /*predmet*/ (): 181, 182–183 void vyradsubmap /*map*/ (): 58, 56–57, 61 void vyradtimer /*timer*/ (): 29, 31, 33 int vyska /*popup*/ : 121, 119–120, 122–124 void vytvor_krk /*kra_krk*/ (): 235 void vytvorcerta /*kra_polic*/ (): 203 void vytvorokno(): 39, 147, 172 void vytvorpredmet(): 182, 242 void vytvorpredmety(): 242, 190, 205 void vytvorpsel(): 123, 122, 163, 165–166 kq_submap *vytvorsubmap(): 57, 64, 175, 205, 208, 222, 232, 234, 237–238 kq_timer vytvortimer(): 33, 27, 65, 68, 73, 167, 207–208, 221–222, 224, 226, 229–236 kq_widget *vytvorwidget(): 45, 68, 167, 179, 203, 205, 224, 228, 232, 234, 237–238 kq_policko *vzamku1: 191, 199–200, 225 kq_policko *vzamku2: 191, 200, 217 int vzdalenost(): 75, 65, 76–78 void warning(): 8, 19, 23, 26–28, 30–31, 36–37, 52, 55, 57–58, 61, 64, 68, 72–74, 81, 83, 87, 89–94, 96–97, 99, 101–104, 107–108, 117–120, 122–123, 127–131, 133–135, 137, 141, 144–146, 152, 154, 156–162, 166, 168, 179–180, 182–185, 187, 211–213, 217, 220–221 Window win: 38, 39–47, 62, 87–88, 113, 117, 119–121, 123, 140, 147, 163, 165–166, 181–182, 186, 188 int win_sirka: 39, 40–43, 119–121, 124, 186 int win_vyska: 39, 40–41, 43, 120–121, 124, 186 int win_x /*window*/ : 39, 40–41, 44 int win_y /*window*/ : 39, 40–41, 44 char *WINDOW_NAME: 10, 40 WORD: 17, 19, 81, 94, 103, 106 WORDCAT: 17, 19, 93, 105–106 WORDPART: 17, 81, 94, 106 void wordtohash(): 94, 91, 105 kq_widget *wprovaz(): 239, 238, 240, 244–245 XIC xic /*keyboard*/ : 22, 23 int void
255
51 Literatura
Program kraluk
xkeyznak(): 23, 25, 120, 164 zalohujtext(): 115, 118, 163 zalomstring /*popup*/ (): 120, 119, 124 void zapalsvicku(): 216, 206 void zapiscs(): 130, 128–129 void zapisznak(): 12, 13, 90, 102–104 void zaradpredmet /*predmet*/ (): 181, 183 void zaradsubmap /*map*/ (): 58, 57, 61 void zaradtimer /*timer*/ (): 29, 30–31, 33 void zavri(): 208, 205 void zdrchal(): 237, 199 kq_predmet *zebrik: 242, 204–205, 208–209, 215, 223, 244 kq_color *zed: 218, 53–54, 63, 69, 77, 174, 217, 222, 239–240 kq_color *zem: 218, 213–214, 217, 220 kq_word *zemisto(): 206, 205 char *zestringuj(): 13, 90, 102, 104 int zjistitimer(): 28, 27, 30, 231 void zkoumejhist(): 115, 20–21, 112, 117 void zkuschytit(): 64, 66, 69 char zkusmluvit /*kra_input*/ (): 214, 213 void zmenanip(): 73, 176, 184, 190, 204, 209, 211, 214, 216, 219, 221–224, 226, 228–231, 235–236, 238–239 void zmenapost(): 66, 69–71, 73, 174, 207–208, 222, 229, 238–239, 241 void zmenbgmap(): 56, 171–172 char
void
void int
void void void char void void void void void char
void
void void
void void void void void void void void
zmenFPS(): 26, 20, 161–162 zmenlang(): 105, 106–108 zmenokno(): 42, 147, 171 zmenprnazev(): 182, 207, 211–212, 215–216, 222 zmensipism(): 14, 15 zmensmer /*bindings*/ (): 21, 20 zmentext(): 117, 163–164 zmentimer(): 30, 27, 231, 238–239 zmizpredmet /*predmet*/ : 184, 182 zmizpredmety(): 184, 173 znak: 206, 200, 208–210, 212, 215–216, 221, 224–229, 235, 237–238, 244–245 znicpost(): 68, 70, 184, 204, 211–212, 214–215, 217, 222–224, 226, 232–234, 238–239 znicsubmap(): 57, 64, 68, 207, 222 znictimer(): 33, 27, 65, 68, 73, 207, 217, 221–222, 226–227, 231, 234, 236, 238 znicwidget(): 49, 68, 212, 233–234, 239 zobrazjazyky(): 108, 20, 217 zobrazpredmet /*predmet*/ (): 183, 181, 184 zobrazpredmety(): 184, 171–172 zobrazwidget /*widget*/ (): 46, 45, 48 zrusjazyk /*languages*/ (): 106 zruspsel(): 123, 165 zrussubmap /*map*/ (): 59, 57, 60–61
51 Literatura [1] Knuth Donald Ervin: The Art of Computer Programming, volume 3 (Sorting and Searching), Second Edition, Addison-Wesley, 1998. [2] Nye Adrian: Xlib Programming Manual for Version 11, volume 1, Third Edition, O’Reilly & Associates, Inc, 1992.
256