diff --git a/campgns/keeporig.cfg b/campgns/keeporig.cfg index ac2f1219eb..adc5b43c3d 100644 --- a/campgns/keeporig.cfg +++ b/campgns/keeporig.cfg @@ -19,8 +19,6 @@ MEDIA_LOCATION = ldata ; Single player level numbers, and bonus levels for 'Reveal hidden land' boxes SINGLE_LEVELS = 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 BONUS_LEVELS = 0 0 0 0 0 0 0 100 101 0 0 0 0 0 102 0 103 104 0 0 -; Multiplayer level numbers (you may also define multiplayer levels using .LOF files) -MULTI_LEVELS = 50 51 52 53 54 60 61 62 63 64 70 71 72 73 74 ; Extra levels: full moon, new moon EXTRA_LEVELS = 105 ; File which stores credits (located in land location folder) @@ -354,112 +352,3 @@ ENSIGN_POS = 757 617 ENSIGN_ZOOM = 757 617 PLAYERS = 1 ENSIGN = - -; Details about multiplayer levels - -[map00050] -NAME_TEXT = Multiplayer 1 -ENSIGN_POS = 820 618 -ENSIGN_ZOOM = 820 618 -PLAYERS = 2 -ENSIGN = - -[map00051] -NAME_TEXT = Multiplayer 2 -ENSIGN_POS = 767 542 -ENSIGN_ZOOM = 767 542 -PLAYERS = 2 -ENSIGN = - -[map00052] -NAME_TEXT = Multiplayer 3 -ENSIGN_POS = 703 616 -ENSIGN_ZOOM = 703 616 -PLAYERS = 2 -ENSIGN = - -[map00053] -NAME_TEXT = Multiplayer 4 -ENSIGN_POS = 795 680 -ENSIGN_ZOOM = 795 680 -PLAYERS = 2 -ENSIGN = - -[map00054] -NAME_TEXT = Multiplayer 5 -ENSIGN_POS = 879 654 -ENSIGN_ZOOM = 879 654 -PLAYERS = 2 -ENSIGN = - -[map00060] -NAME_TEXT = Multiplayer 6 -ENSIGN_POS = 445 530 -ENSIGN_ZOOM = 445 530 -PLAYERS = 3 -ENSIGN = - -[map00061] -NAME_TEXT = Multiplayer 7 -ENSIGN_POS = 453 594 -ENSIGN_ZOOM = 453 594 -PLAYERS = 3 -ENSIGN = - -[map00062] -NAME_TEXT = Multiplayer 8 -ENSIGN_POS = 529 578 -ENSIGN_ZOOM = 529 578 -PLAYERS = 3 -ENSIGN = - -[map00063] -NAME_TEXT = Multiplayer 9 -ENSIGN_POS = 433 706 -ENSIGN_ZOOM = 433 706 -PLAYERS = 3 -ENSIGN = - -[map00064] -NAME_TEXT = Multiplayer 10 -ENSIGN_POS = 500 692 -ENSIGN_ZOOM = 500 692 -PLAYERS = 3 -ENSIGN = - -[map00070] -NAME_TEXT = Multiplayer 11 -ENSIGN_POS = 520 385 -ENSIGN_ZOOM = 520 385 -PLAYERS = 4 -ENSIGN = - -[map00071] -NAME_TEXT = Multiplayer 12 -ENSIGN_POS = 590 385 -ENSIGN_ZOOM = 590 385 -PLAYERS = 4 -ENSIGN = - -[map00072] -NAME_TEXT = Multiplayer 13 -ENSIGN_POS = 634 405 -ENSIGN_ZOOM = 634 405 -PLAYERS = 4 -ENSIGN = - -[map00073] -NAME_TEXT = Multiplayer 14 -ENSIGN_POS = 676 429 -ENSIGN_ZOOM = 676 429 -PLAYERS = 4 -ENSIGN = - -[map00074] -NAME_TEXT = Multiplayer 15 -ENSIGN_POS = 664 357 -ENSIGN_ZOOM = 664 357 -PLAYERS = 4 -ENSIGN = - - diff --git a/mpmaps/campgn_order.txt b/mpmaps/campgn_order.txt new file mode 100644 index 0000000000..fbc3342d80 --- /dev/null +++ b/mpmaps/campgn_order.txt @@ -0,0 +1,14 @@ +#order of the campaigns, campaigns not in the list will be at the bottom alphabetically +keeporig.cfg +origplus.cfg +burdnimp.cfg +undedkpr.cfg +pstunded.cfg +lqizgood.cfg +revlord.cfg +ami2019.cfg +twinkprs.cfg +ancntkpr.cfg +postanck.cfg +dzjr06lv.cfg +jdkmaps8.cfg diff --git a/mpmaps/keeporig.cfg b/mpmaps/keeporig.cfg new file mode 100644 index 0000000000..44e677bf56 --- /dev/null +++ b/mpmaps/keeporig.cfg @@ -0,0 +1,215 @@ +; KeeperFX campaign file +; Modify this file to create your own DK campaigns. + +[common] +NAME = Dungeon Keeper original campaign +; Name of the campaign from the GUI text file. Remove or leave empty if unavailable. +NAME_TEXT_ID = 1011 +; Folders storing data files for this campaign +LEVELS_LOCATION = mpmaps/keeporig +LAND_LOCATION = campgns/keeporig_lnd +; If you wish your campaign to have standard creatures, remove the blow line. If you have campaign +; specific creatures place them in a folder you define here. +CREATURES_LOCATION = levels/classic_crtr +; If you wish your campaign to have customized rules and other configs, define a new folder below. +; Remove the line to get KeeperFX standard rules, otherwise you'll get the classic rules. +CONFIGS_LOCATION = levels/classic_cfgs +; If you wish your campaign to have custom in-game speeches, movies, sounds or music you should set their location +MEDIA_LOCATION = ldata +; Single player level numbers, and bonus levels for 'Reveal hidden land' boxes +; Note that, for now, only up to 6 bonus levels is supported +SINGLE_LEVELS = 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +BONUS_LEVELS = 0 0 0 0 0 0 0 100 101 0 0 0 0 0 102 0 103 104 0 0 +; Multiplayer level numbers (you may also define multiplayer levels using .LOF files) +MULTI_LEVELS = 50 51 52 53 54 60 61 62 63 64 70 71 72 73 74 +; Extra levels: full moon, new moon +EXTRA_LEVELS = 105 +; File which stores credits (located in land location folder) +CREDITS = dkcredts.txt +; High score table parameters (num of entries and file name) +HIGH_SCORES = 9999 scr_dkpr.dat +; Land view at start and end of the game +LAND_VIEW_START = rgmap00 viframe00 +LAND_VIEW_END = rgmap21 viframe21 +; The sprites used for marking locations which can be clicked. ENSIGNS or PINPOINTS. +LAND_MARKERS = ENSIGNS +; Ambient sound samples - good and bad sound +LAND_AMBIENT = 189 190 +; Intro and outro; note that the intro here is for campaign, not for whole game; +; the files should be placed in MEDIA_LOCATION folder +;INTRO_MOVIE = +OUTRO_MOVIE = outromix.smk +; Player number to use for human player in this campaing's levels. +; Valid values are: RED, BLUE, GREEN, YELLOW, WHITE, PURPLE, BLACK, ORANGE +HUMAN_PLAYER = RED +; Landview music. Can be a track number, or a filename in media location. +SOUNDTRACK = 2 + +; Text strings file used for ingame info messages and objectives (not for GUI) +; The file can contain up to 1024 strings, separated by null character. +; If there's no file for current language, then first entry is selected by default. +; If your campaign supports only one language, you may comment out all lines but one. +; If the campaign doesn't use custom strings file, then leave this section unchanged. +[strings] +ENG = fxdata/gtext_eng.dat +FRE = fxdata/gtext_fre.dat +GER = fxdata/gtext_ger.dat +ITA = fxdata/gtext_ita.dat +SPA = fxdata/gtext_spa.dat +SWE = fxdata/gtext_swe.dat +POL = fxdata/gtext_pol.dat +DUT = fxdata/gtext_dut.dat +JPN = fxdata/gtext_jpn.dat +CHI = fxdata/gtext_chi.dat +CHT = fxdata/gtext_cht.dat +RUS = fxdata/gtext_rus.dat +CZE = fxdata/gtext_cze.dat +KOR = fxdata/gtext_kor.dat +UKR = fxdata/gtext_ukr.dat +LAT = fxdata/gtext_lat.dat +;HUN = fxdata/gtext_hun.dat +;DAN = fxdata/gtext_dan.dat +;NOR = fxdata/gtext_nor.dat +;ARA = fxdata/gtext_ara.dat + +; Location of the speech sound files. +; If there's no folder for current language, then first entry is selected by default. +[speech] +ENG = campgns/keeporig_eng +FRE = campgns/keeporig_fre +GER = campgns/keeporig_ger +ITA = campgns/keeporig_ita +SPA = campgns/keeporig_spa +SWE = campgns/keeporig_swe +POL = campgns/keeporig_pol +DUT = campgns/keeporig_dut +JPN = campgns/keeporig_jpn +CHI = campgns/keeporig_chi +CHT = campgns/keeporig_cht +RUS = campgns/keeporig_rus +KOR = campgns/keeporig_kor + +; Details about levels will follow. Only sections mentioned in [common] block +; will be parsed by the game; other blocks are skipped. +; NAME_IDs are message IDs from strings file. +; Note that NAME_TEXTs are not used if NAME_IDs are present. +; ENSIGN_POS is a position on the Land View screen, X is ranged 160..1120, +; while Y is 120..840. At this exact point, the bottom centre of the ensign +; sprite is placed. ENSIGN_ZOOM is the place which is zoomed when the ensign +; is selected; it is usually the same place where ensign is, but may be moved +; a few pixels if this gives better graphics result. +; LAND_VIEW option should be only present in single player levels. +; SPEECH is the voice of the mentor before and after the level. MP3, Ogg, VOC, +; FLAC and WAV formats are supported. + +; Details about single player levels + + +; Details about multiplayer levels + +[map00050] +NAME_TEXT = Multiplayer 1 +ENSIGN_POS = 820 618 +ENSIGN_ZOOM = 820 618 +PLAYERS = 2 +OPTIONS = + +[map00051] +NAME_TEXT = Multiplayer 2 +ENSIGN_POS = 767 542 +ENSIGN_ZOOM = 767 542 +PLAYERS = 2 +OPTIONS = + +[map00052] +NAME_TEXT = Multiplayer 3 +ENSIGN_POS = 703 616 +ENSIGN_ZOOM = 703 616 +PLAYERS = 2 +OPTIONS = + +[map00053] +NAME_TEXT = Multiplayer 4 +ENSIGN_POS = 795 680 +ENSIGN_ZOOM = 795 680 +PLAYERS = 2 +OPTIONS = + +[map00054] +NAME_TEXT = Multiplayer 5 +ENSIGN_POS = 879 654 +ENSIGN_ZOOM = 879 654 +PLAYERS = 2 +OPTIONS = + +[map00060] +NAME_TEXT = Multiplayer 6 +ENSIGN_POS = 445 530 +ENSIGN_ZOOM = 445 530 +PLAYERS = 3 +OPTIONS = + +[map00061] +NAME_TEXT = Multiplayer 7 +ENSIGN_POS = 453 594 +ENSIGN_ZOOM = 453 594 +PLAYERS = 3 +OPTIONS = + +[map00062] +NAME_TEXT = Multiplayer 8 +ENSIGN_POS = 529 578 +ENSIGN_ZOOM = 529 578 +PLAYERS = 3 +OPTIONS = + +[map00063] +NAME_TEXT = Multiplayer 9 +ENSIGN_POS = 433 706 +ENSIGN_ZOOM = 433 706 +PLAYERS = 3 +OPTIONS = + +[map00064] +NAME_TEXT = Multiplayer 10 +ENSIGN_POS = 500 692 +ENSIGN_ZOOM = 500 692 +PLAYERS = 3 +OPTIONS = + +[map00070] +NAME_TEXT = Multiplayer 11 +ENSIGN_POS = 520 385 +ENSIGN_ZOOM = 520 385 +PLAYERS = 4 +OPTIONS = + +[map00071] +NAME_TEXT = Multiplayer 12 +ENSIGN_POS = 590 385 +ENSIGN_ZOOM = 590 385 +PLAYERS = 4 +OPTIONS = + +[map00072] +NAME_TEXT = Multiplayer 13 +ENSIGN_POS = 634 405 +ENSIGN_ZOOM = 634 405 +PLAYERS = 4 +OPTIONS = + +[map00073] +NAME_TEXT = Multiplayer 14 +ENSIGN_POS = 676 429 +ENSIGN_ZOOM = 676 429 +PLAYERS = 4 +OPTIONS = + +[map00074] +NAME_TEXT = Multiplayer 15 +ENSIGN_POS = 664 357 +ENSIGN_ZOOM = 664 357 +PLAYERS = 4 +OPTIONS = + + diff --git a/campgns/keeporig/map00050.txt b/mpmaps/keeporig/map00050.txt similarity index 100% rename from campgns/keeporig/map00050.txt rename to mpmaps/keeporig/map00050.txt diff --git a/campgns/keeporig/map00051.txt b/mpmaps/keeporig/map00051.txt similarity index 100% rename from campgns/keeporig/map00051.txt rename to mpmaps/keeporig/map00051.txt diff --git a/campgns/keeporig/map00052.txt b/mpmaps/keeporig/map00052.txt similarity index 100% rename from campgns/keeporig/map00052.txt rename to mpmaps/keeporig/map00052.txt diff --git a/campgns/keeporig/map00053.txt b/mpmaps/keeporig/map00053.txt similarity index 100% rename from campgns/keeporig/map00053.txt rename to mpmaps/keeporig/map00053.txt diff --git a/campgns/keeporig/map00054.txt b/mpmaps/keeporig/map00054.txt similarity index 100% rename from campgns/keeporig/map00054.txt rename to mpmaps/keeporig/map00054.txt diff --git a/campgns/keeporig/map00055.txt b/mpmaps/keeporig/map00055.txt similarity index 100% rename from campgns/keeporig/map00055.txt rename to mpmaps/keeporig/map00055.txt diff --git a/campgns/keeporig/map00056.txt b/mpmaps/keeporig/map00056.txt similarity index 100% rename from campgns/keeporig/map00056.txt rename to mpmaps/keeporig/map00056.txt diff --git a/campgns/keeporig/map00057.txt b/mpmaps/keeporig/map00057.txt similarity index 100% rename from campgns/keeporig/map00057.txt rename to mpmaps/keeporig/map00057.txt diff --git a/campgns/keeporig/map00058.txt b/mpmaps/keeporig/map00058.txt similarity index 100% rename from campgns/keeporig/map00058.txt rename to mpmaps/keeporig/map00058.txt diff --git a/campgns/keeporig/map00059.txt b/mpmaps/keeporig/map00059.txt similarity index 100% rename from campgns/keeporig/map00059.txt rename to mpmaps/keeporig/map00059.txt diff --git a/campgns/keeporig/map00060.txt b/mpmaps/keeporig/map00060.txt similarity index 100% rename from campgns/keeporig/map00060.txt rename to mpmaps/keeporig/map00060.txt diff --git a/campgns/keeporig/map00061.txt b/mpmaps/keeporig/map00061.txt similarity index 100% rename from campgns/keeporig/map00061.txt rename to mpmaps/keeporig/map00061.txt diff --git a/campgns/keeporig/map00062.txt b/mpmaps/keeporig/map00062.txt similarity index 100% rename from campgns/keeporig/map00062.txt rename to mpmaps/keeporig/map00062.txt diff --git a/campgns/keeporig/map00063.txt b/mpmaps/keeporig/map00063.txt similarity index 100% rename from campgns/keeporig/map00063.txt rename to mpmaps/keeporig/map00063.txt diff --git a/campgns/keeporig/map00064.txt b/mpmaps/keeporig/map00064.txt similarity index 100% rename from campgns/keeporig/map00064.txt rename to mpmaps/keeporig/map00064.txt diff --git a/campgns/keeporig/map00065.txt b/mpmaps/keeporig/map00065.txt similarity index 100% rename from campgns/keeporig/map00065.txt rename to mpmaps/keeporig/map00065.txt diff --git a/campgns/keeporig/map00066.txt b/mpmaps/keeporig/map00066.txt similarity index 100% rename from campgns/keeporig/map00066.txt rename to mpmaps/keeporig/map00066.txt diff --git a/campgns/keeporig/map00067.txt b/mpmaps/keeporig/map00067.txt similarity index 100% rename from campgns/keeporig/map00067.txt rename to mpmaps/keeporig/map00067.txt diff --git a/campgns/keeporig/map00068.txt b/mpmaps/keeporig/map00068.txt similarity index 100% rename from campgns/keeporig/map00068.txt rename to mpmaps/keeporig/map00068.txt diff --git a/campgns/keeporig/map00069.txt b/mpmaps/keeporig/map00069.txt similarity index 100% rename from campgns/keeporig/map00069.txt rename to mpmaps/keeporig/map00069.txt diff --git a/campgns/keeporig/map00070.txt b/mpmaps/keeporig/map00070.txt similarity index 100% rename from campgns/keeporig/map00070.txt rename to mpmaps/keeporig/map00070.txt diff --git a/campgns/keeporig/map00071.txt b/mpmaps/keeporig/map00071.txt similarity index 100% rename from campgns/keeporig/map00071.txt rename to mpmaps/keeporig/map00071.txt diff --git a/campgns/keeporig/map00072.txt b/mpmaps/keeporig/map00072.txt similarity index 100% rename from campgns/keeporig/map00072.txt rename to mpmaps/keeporig/map00072.txt diff --git a/campgns/keeporig/map00073.txt b/mpmaps/keeporig/map00073.txt similarity index 100% rename from campgns/keeporig/map00073.txt rename to mpmaps/keeporig/map00073.txt diff --git a/campgns/keeporig/map00074.txt b/mpmaps/keeporig/map00074.txt similarity index 100% rename from campgns/keeporig/map00074.txt rename to mpmaps/keeporig/map00074.txt diff --git a/campgns/keeporig/map00075.txt b/mpmaps/keeporig/map00075.txt similarity index 100% rename from campgns/keeporig/map00075.txt rename to mpmaps/keeporig/map00075.txt diff --git a/campgns/keeporig/map00076.txt b/mpmaps/keeporig/map00076.txt similarity index 100% rename from campgns/keeporig/map00076.txt rename to mpmaps/keeporig/map00076.txt diff --git a/campgns/keeporig/map00077.txt b/mpmaps/keeporig/map00077.txt similarity index 100% rename from campgns/keeporig/map00077.txt rename to mpmaps/keeporig/map00077.txt diff --git a/campgns/keeporig/map00078.txt b/mpmaps/keeporig/map00078.txt similarity index 100% rename from campgns/keeporig/map00078.txt rename to mpmaps/keeporig/map00078.txt diff --git a/campgns/keeporig/map00079.txt b/mpmaps/keeporig/map00079.txt similarity index 100% rename from campgns/keeporig/map00079.txt rename to mpmaps/keeporig/map00079.txt diff --git a/src/config.c b/src/config.c index 9c174aa912..312d7f1dd3 100644 --- a/src/config.c +++ b/src/config.c @@ -1356,6 +1356,10 @@ char *prepare_file_path_buf_mod(char *dst, int dst_size, const char *mod_dir, sh mdir=keeper_runtime_directory; sdir="creatrs"; break; + case FGrp_MpLevels: + mdir=keeper_runtime_directory; + sdir="mpmaps"; + break; default: mdir="./"; sdir=NULL; diff --git a/src/config.h b/src/config.h index 1d3c09d328..502bf52cd3 100644 --- a/src/config.h +++ b/src/config.h @@ -61,6 +61,7 @@ enum TbFileGroups { FGrp_CmpgConfig, FGrp_CmpgMedia, FGrp_Music, + FGrp_MpLevels, }; enum TbExtraLevels { diff --git a/src/config_campaigns.c b/src/config_campaigns.c index f71504472e..0048af2361 100644 --- a/src/config_campaigns.c +++ b/src/config_campaigns.c @@ -66,6 +66,7 @@ const struct NamedCommand cmpgn_common_commands[] = { {"NAME_TEXT_ID", 20}, {"ASSIGN_CPU_KEEPERS", 21}, {"SOUNDTRACK", 22}, + {"LOBBY_NAME", 23}, {NULL, 0}, }; @@ -130,7 +131,10 @@ const struct NamedCommand cmpgn_human_player_options[] = { struct GameCampaign campaign; struct CampaignsList campaigns_list; struct CampaignsList mappacks_list; +struct CampaignsList mp_mappacks_list; + +static TbBool check_lif_files_in_mappack(struct GameCampaign *campgn,unsigned long * out_count); /******************************************************************************/ /* * Frees campaign sub-entries memory without NULLing invalid pointers. @@ -434,6 +438,7 @@ short parse_campaign_common_blocks(struct GameCampaign *campgn,char *buf,long le else { snprintf(campgn->display_name, LINEMSG_SIZE, "%s", campgn->name); + snprintf(campgn->lobby_name, LINEMSG_SIZE, "%s", campgn->name); } break; case 2: // SINGLE_LEVELS @@ -698,6 +703,14 @@ short parse_campaign_common_blocks(struct GameCampaign *campgn,char *buf,long le COMMAND_TEXT(cmd_num), campgn->name, config_textname); } break; + case 23: // LOBBY_NAME + i = get_conf_parameter_whole(buf,&pos,len,campgn->lobby_name,LINEMSG_SIZE); + if (i <= 0) + { + CONFWRNLOG("Couldn't read \"%s\" command parameter in %s %s file.", + COMMAND_TEXT(cmd_num), campgn->lobby_name, config_textname); + } + break; case ccr_comment: break; case ccr_endOfFile: @@ -1142,7 +1155,9 @@ TbBool load_campaign(const char *cmpgn_fname,struct GameCampaign *campgn,unsigne } } if (result && fgroup == FGrp_Campgn) - return (campgn->single_levels_count > 0) || (campgn->multi_levels_count > 0); + return (campgn->single_levels_count > 0); + if (result && fgroup == FGrp_MpLevels) + return (campgn->multi_levels_count > 0); if (result && fgroup == FGrp_VarLevels){ return (true); } @@ -1160,26 +1175,15 @@ TbBool change_campaign(const char *cmpgn_fname) short fgroup = FGrp_Campgn; //use this as a default if (is_campaign_in_list(cmpgn_fname, &mappacks_list)) // check if this is a map pack CFG file fgroup = FGrp_VarLevels; + else if (is_campaign_in_list(cmpgn_fname, &mp_mappacks_list)) // check if this is a map pack CFG file + fgroup = FGrp_MpLevels; if ((cmpgn_fname != NULL) && (cmpgn_fname[0] != '\0')) result = load_campaign(cmpgn_fname,&campaign,CnfLd_Standard, fgroup); else result = load_campaign(keeper_campaign_file,&campaign,CnfLd_Standard, FGrp_Campgn); - // Configs which may change within a level should be initialized outside - //load_stats_files(); - //check_and_auto_fix_stats(); - // Make sure all additional levels are loaded - // Only the original campaign need to list the multiplayer levels - // (until there are multiplayer mappacks) as all multi maps go on - // the same "campaign" screen (and need to be in the same list to do so) - if (strcasecmp(campaign.fname,keeper_campaign_file) == 0) - { - find_and_load_lof_files(); - } - if (fgroup == FGrp_VarLevels) - { - find_and_load_lof_files(); - find_and_load_lif_files(); - } + + find_and_load_lof_files(); + find_and_load_lif_files(); load_or_create_high_score_table(); // Update GUI arrays to new config update_room_tab_to_config(); @@ -1249,10 +1253,17 @@ TbBool load_campaign_to_list(const char *cmpgn_fname,struct CampaignsList *clist struct GameCampaign* campgn = &clist->items[clist->items_num]; if (load_campaign(cmpgn_fname,campgn,CnfLd_ListOnly, fgroup)) { + JUSTLOG("Loaded campaign file: %s",campgn->fname); switch(fgroup) { case FGrp_VarLevels: - if (check_lif_files_in_mappack(campgn)) { // if this returns false, then the map pack is "empty" + if (check_lif_files_in_mappack(campgn,&campaign.freeplay_levels_count)) { // if this returns false, then the map pack is "empty" + clist->items_num++; + return true; + } + break; + case FGrp_MpLevels: + if (check_lif_files_in_mappack(campgn,&campaign.multi_levels_count)) { // if this returns false, then the map pack is "empty" clist->items_num++; return true; } @@ -1346,20 +1357,21 @@ void sort_campaigns(struct CampaignsList *clist,const char* sort_fname) sort_campaigns_quicksort(clist, beg, clist->items_num); } + /** * Searches for campaign files and creates a list of campaigns. */ -TbBool load_campaigns_list(void) +TbBool load_campaigns_list(struct CampaignsList *clist, short fgroup, const char* list_name, const char* order_fname) { - init_campaigns_list_entries(&campaigns_list, CAMPAIGNS_LIST_GROW_DELTA); - char* fname = prepare_file_path(FGrp_Campgn, "*.cfg"); // add campaigns + init_campaigns_list_entries(clist, CAMPAIGNS_LIST_GROW_DELTA); + char* fname = prepare_file_path(fgroup, "*.cfg"); // add campaigns struct TbFileEntry fe; struct TbFileFind * ff = LbFileFindFirst(fname, &fe); long cnum_all = 0; long cnum_ok = 0; if (ff) { do { - if (load_campaign_to_list(fe.Filename, &campaigns_list, FGrp_Campgn)) + if (load_campaign_to_list(fe.Filename, clist, fgroup)) { cnum_ok++; } @@ -1367,41 +1379,21 @@ TbBool load_campaigns_list(void) } while (LbFileFindNext(ff, &fe) >= 0); LbFileFindEnd(ff); } - SYNCDBG(0,"Found %ld campaign files, properly loaded %ld.",cnum_all,cnum_ok); - const char* ordfname = prepare_file_path(FGrp_Campgn, "campgn_order.txt"); - sort_campaigns(&campaigns_list,ordfname); - return (campaigns_list.items_num > 0); + SYNCDBG(0,"Found %ld %s files, properly loaded %ld.",cnum_all,list_name,cnum_ok); + const char* ordfname = prepare_file_path(fgroup, order_fname); + sort_campaigns(clist,ordfname); + return (clist->items_num > 0); } -/** - * Searches for map pack files and creates a list of map packs. - */ -TbBool load_mappacks_list(void) +void set_default_mp_mappack(void) { - init_campaigns_list_entries(&mappacks_list, CAMPAIGNS_LIST_GROW_DELTA); - char* fname = prepare_file_path(FGrp_VarLevels, "*.cfg"); // add map packs - struct TbFileEntry fe; - struct TbFileFind * ff = LbFileFindFirst(fname, &fe); - long cnum_all = 0; - long cnum_ok = 0; - if (ff) { - do { - if (is_campaign_in_list(fe.Filename, &campaigns_list)) - { - WARNMSG("Couldn't load Map Pack \"%s\", as it is a duplicate of an existing Campaign.", fe.Filename); - } - else if (load_campaign_to_list(fe.Filename, &mappacks_list, FGrp_VarLevels)) - { - cnum_ok++; - } - cnum_all++; - } while (LbFileFindNext(ff, &fe) >= 0); - LbFileFindEnd(ff); + if (mp_mappacks_list.items_count < 1) + { + ERRORLOG("No MP Map Packs available to set as default."); + return; } - SYNCDBG(0,"Found %ld map pack files, properly loaded %ld.",cnum_all,cnum_ok); - const char* ordfname = prepare_file_path(FGrp_VarLevels, "mappck_order.txt"); - sort_campaigns(&mappacks_list,ordfname); - return (mappacks_list.items_num > 0); + + change_campaign(mp_mappacks_list.items[0].fname); } TbBool is_campaign_in_list(const char *cmpgn_fname, struct CampaignsList *clist) @@ -1420,14 +1412,14 @@ TbBool is_campaign_in_list(const char *cmpgn_fname, struct CampaignsList *clist) return false; } -TbBool check_lif_files_in_mappack(struct GameCampaign *campgn) +static TbBool check_lif_files_in_mappack(struct GameCampaign *campgn,unsigned long * out_count) { struct GameCampaign campbuf; memcpy(&campbuf, &campaign, sizeof(struct GameCampaign)); memcpy(&campaign, campgn, sizeof(struct GameCampaign)); find_and_load_lif_files(); find_and_load_lof_files(); - TbBool result = (campaign.freeplay_levels_count != 0); + TbBool result = (*out_count != 0); if (!result) { // Could be either: no valid levels in LEVELS_LOCATION, no LEVELS_LOCATION specified, or LEVELS_LOCATION does not exist WARNMSG("Couldn't load Map Pack \"%s\", no .LIF files could be found.", campgn->fname); diff --git a/src/config_campaigns.h b/src/config_campaigns.h index 2ea01af5ed..390e755e34 100644 --- a/src/config_campaigns.h +++ b/src/config_campaigns.h @@ -72,6 +72,7 @@ struct GameCampaign { char name[LINEMSG_SIZE]; char display_name[LINEMSG_SIZE]; char fname[DISKPATH_SIZE]; + char lobby_name[LINEMSG_SIZE]; char levels_location[DISKPATH_SIZE]; char speech_location[DISKPATH_SIZE]; char land_location[DISKPATH_SIZE]; @@ -160,6 +161,7 @@ struct CampaignsList { extern struct GameCampaign campaign; extern struct CampaignsList campaigns_list; extern struct CampaignsList mappacks_list; +extern struct CampaignsList mp_mappacks_list; extern const struct NamedCommand cmpgn_map_commands[]; extern const struct NamedCommand cmpgn_map_ensign_flag_options[]; extern const struct NamedCommand cmpgn_map_cmnds_kind[]; @@ -180,13 +182,12 @@ struct LevelInformation *new_level_info_entry(struct GameCampaign *campgn, Level // Support for lists of campaigns TbBool init_campaigns_list_entries(struct CampaignsList *clist, long num_entries); TbBool grow_campaigns_list_entries(struct CampaignsList *clist, long add_entries); -TbBool load_campaigns_list(void); -TbBool load_mappacks_list(void); +TbBool load_campaigns_list(struct CampaignsList *clist, short fgroup, const char* list_name, const char* order_fname); TbBool change_campaign(const char *cmpgn_fname); TbBool is_campaign_loaded(void); TbBool is_campaign_in_list(const char *cmpgn_fname, struct CampaignsList *clist); -TbBool check_lif_files_in_mappack(struct GameCampaign *campgn); TbBool is_map_pack(void); +void set_default_mp_mappack(void); /******************************************************************************/ #ifdef __cplusplus } diff --git a/src/front_landview.c b/src/front_landview.c index ca203d34de..49dbd4902b 100644 --- a/src/front_landview.c +++ b/src/front_landview.c @@ -103,6 +103,12 @@ long players_currently_in_session; /******************************************************************************/ void draw_map_screen(void) { + if (map_screen == NULL) + { + ERRORLOG("Map screen buffer is not allocated"); + return; + } + copy_raw8_image_buffer(lbDisplay.WScreen,LbGraphicsScreenWidth(),LbGraphicsScreenHeight(), scale_value_landview(LANDVIEW_MAP_WIDTH), scale_value_landview(LANDVIEW_MAP_HEIGHT), -scale_value_landview(map_info.screen_shift_x), -scale_value_landview(map_info.screen_shift_y), @@ -216,12 +222,17 @@ void update_net_ensigns_visibility(void) SYNCDBG(18, "Starting"); set_all_ensigns_state(LvSt_Hidden); long lvnum = first_multiplayer_level(); + int16_t i = 0; while (lvnum > 0) { struct LevelInformation* lvinfo = get_level_info(lvnum); if (lvinfo != NULL) lvinfo->state = LvSt_Visible; lvnum = next_multiplayer_level(lvnum); + if (++i > MULTI_LEVELS_COUNT) { + ERRORLOG("Breaking infinite loop in update_net_ensigns_visibility"); + break; + } } } @@ -971,13 +982,7 @@ TbBool load_map_and_window(LevelNumber lvnum) void frontnet_init_level_descriptions(void) { - //TODO NETWORK Don't allow campaigns besides original - we don't have per-campaign MP yet - //if (!is_campaign_loaded()) - { - if (!change_campaign("")) { - return; - } - } + } void frontnetmap_unload(void) diff --git a/src/front_network.c b/src/front_network.c index 9fa22e038c..4cb7a6981d 100644 --- a/src/front_network.c +++ b/src/front_network.c @@ -357,6 +357,42 @@ void frontnet_reset_ping_stabilization(void) previous_player_count_for_ping_wait = -1; } +static int message_char_index = -1; +static int message_length = 0; +static char auto_message[64] = ""; + +void set_auto_message(const char* msg) +{ + strncpy(auto_message, msg, sizeof(auto_message)-1); + auto_message[sizeof(auto_message)-1] = '\0'; + message_length = strlen(auto_message); + message_char_index = 0; +} + +static void send_stored_message() +{ + // Send message one character per frame + if (message_char_index >= 0) { + struct ScreenPacket *nspck; + nspck = &net_screen_packet[my_player_number]; + if ((nspck->networkstatus_flags & 0xF8) == 0) { + if (message_char_index < message_length) { + // Send next character directly to message buffer + struct PlayerInfo *player = get_my_player(); + if (message_char_index < PLAYER_MP_MESSAGE_LEN - 1) { + player->mp_message_text[message_char_index] = auto_message[message_char_index]; + player->mp_message_text[message_char_index + 1] = '\0'; + } + message_char_index++; + } else { + // Message complete, trigger send + lbInkey = KC_RETURN; + message_char_index = -1; // Reset for next time + } + } + } +} + void handle_autostart_multiplayer_messaging(void) { static TbBool send_pending = false; @@ -402,6 +438,7 @@ void frontnet_start_update(void) } handle_autostart_multiplayer_messaging(); + send_stored_message(); if ((net_number_of_messages <= 0) || (net_message_scroll_offset < 0)) { diff --git a/src/front_network.h b/src/front_network.h index dfb0eced67..860e8116f8 100644 --- a/src/front_network.h +++ b/src/front_network.h @@ -57,6 +57,8 @@ void frontnet_reset_ping_stabilization(void); void net_load_config_file(void); void net_write_config_file(void); + +void set_auto_message(const char* msg); /******************************************************************************/ #ifdef __cplusplus } diff --git a/src/frontend.cpp b/src/frontend.cpp index ef72d56884..31db1080cb 100644 --- a/src/frontend.cpp +++ b/src/frontend.cpp @@ -206,6 +206,7 @@ struct GuiMenu *menu_list[] = { &spell_menu2, &room_menu2, &trap_menu2, + &frontend_select_mp_mappack_menu, NULL, }; @@ -1548,6 +1549,29 @@ void frontend_draw_computer_players(struct GuiButton *gbtn) lbDisplay.DrawFlags = 0; } + +void frontend_draw_mp_mappack(struct GuiButton *gbtn) +{ + int font_idx; + font_idx = frontend_button_caption_font(gbtn,frontend_mouse_over_button); + LbTextSetFont(frontend_font[font_idx]); + const char *text; + text = campaign.lobby_name; + + int tx_units_per_px; + tx_units_per_px = gbtn->height * 16 / LbTextLineHeight(); + int ln_height; + ln_height = LbTextLineHeight() * tx_units_per_px / 16; + LbTextSetWindow(gbtn->scr_pos_x, gbtn->scr_pos_y, gbtn->width, ln_height); + lbDisplay.DrawFlags = Lb_TEXT_HALIGN_LEFT; + //LbTextDrawResized(0, 0, tx_units_per_px, frontend_button_caption_text(gbtn)); + //TODO needs translatable string + LbTextDrawResized(0, 0, tx_units_per_px, "Mappack:"); + lbDisplay.DrawFlags = Lb_TEXT_HALIGN_RIGHT; + LbTextDrawResized(0, 0, tx_units_per_px, text); + lbDisplay.DrawFlags = 0; +} + void set_packet_start(struct GuiButton *gbtn) { struct ScreenPacket *nspck; @@ -1805,6 +1829,32 @@ void frontend_load_mappacks(struct GuiButton *gbtn) } } +void frontend_load_mp_mappacks(struct GuiButton *gbtn) +{ + const char *cmpgn_fname; + SYNCDBG(6,"Clicked"); + // Check if we can show some levels without showing the map pack selection screen + if (mp_mappacks_list.items_num < 1) + cmpgn_fname = ""; + else + if (mp_mappacks_list.items_num == 1) + cmpgn_fname = mp_mappacks_list.items[0].fname; + else + cmpgn_fname = NULL; + if (cmpgn_fname != NULL) + { // If there's only one map pack, then just show the levels + if (!change_campaign(cmpgn_fname)) + { + ERRORLOG("Unable to load map pack list"); + return; + } + frontend_set_state(FeSt_LEVEL_SELECT); + } else + { // If there's more map packs, go to selection screen + frontend_set_state(FeSt_MP_MAPPACK_SELECT); + } +} + /** * Writes the continue game file. * If allow_lvnum_grow is true and my_player has won the singleplayer level, @@ -2059,6 +2109,7 @@ short is_toggleable_menu(short mnu_idx) case GMnu_MAPPACK_SELECT: case GMnu_FECAMPAIGN_SELECT: case GMnu_FEERROR_BOX: + case GMnu_MP_MAPPACK_SELECT: return false; default: return true; @@ -2740,6 +2791,9 @@ void frontend_shutdown_state(FrontendMenuState pstate) case FeSt_CAMPAIGN_SELECT: turn_off_menu(GMnu_FECAMPAIGN_SELECT); break; + case FeSt_MP_MAPPACK_SELECT: + turn_off_menu(GMnu_MP_MAPPACK_SELECT); + break; case FeSt_START_KPRLEVEL: case FeSt_START_MPLEVEL: case FeSt_QUIT_GAME: @@ -2891,6 +2945,11 @@ FrontendMenuState frontend_setup_state(FrontendMenuState nstate) frontend_campaign_list_load(); set_pointer_graphic_menu(); break; + case FeSt_MP_MAPPACK_SELECT: + turn_on_menu(GMnu_MP_MAPPACK_SELECT); + frontend_mp_mappack_list_load(); + set_pointer_graphic_menu(); + break; #if (BFDEBUG_LEVEL > 0) case FeSt_FONT_TEST: fade_palette_in = 0; @@ -2943,6 +3002,7 @@ static const char * menu_state_str(FrontendMenuState state) case FeSt_DRAG: return "FeSt_DRAG"; case FeSt_CAMPAIGN_INTRO: return "FeSt_CAMPAIGN_INTRO"; case FeSt_MAPPACK_SELECT: return "FeSt_MAPPACK_SELECT"; + case FeSt_MP_MAPPACK_SELECT: return "FeSt_MP_MAPPACK_SELECT"; case FeSt_FONT_TEST: return "FeSt_FONT_TEST"; } return "unknown"; @@ -3441,6 +3501,7 @@ short frontend_draw(void) case FeSt_LEVEL_SELECT: case FeSt_MAPPACK_SELECT: case FeSt_CAMPAIGN_SELECT: + case FeSt_MP_MAPPACK_SELECT: frontend_copy_background(); draw_gui(); break; diff --git a/src/frontend.h b/src/frontend.h index 4525dba9bf..2bc433aea3 100644 --- a/src/frontend.h +++ b/src/frontend.h @@ -30,7 +30,7 @@ extern "C" { /******************************************************************************/ // Limits for GUI arrays #define ACTIVE_BUTTONS_COUNT 86 -#define MENU_LIST_ITEMS_COUNT 51 +#define MENU_LIST_ITEMS_COUNT 52 #define FRONTEND_BUTTON_INFO_COUNT 113 #define NET_MESSAGES_COUNT 8 #define NET_MESSAGE_LEN 64 @@ -85,6 +85,7 @@ enum FrontendMenuStates { FeSt_DRAG, FeSt_CAMPAIGN_INTRO, FeSt_MAPPACK_SELECT, + FeSt_MP_MAPPACK_SELECT, // Special testing states FeSt_FONT_TEST = 255, }; @@ -361,6 +362,7 @@ void frontend_draw_enter_text(struct GuiButton *gbtn); void frontend_draw_small_menu_button(struct GuiButton *gbtn); void frontend_toggle_computer_players(struct GuiButton *gbtn); void frontend_draw_computer_players(struct GuiButton *gbtn); +void frontend_draw_mp_mappack(struct GuiButton *gbtn); void set_packet_start(struct GuiButton *gbtn); void gui_area_scroll_window(struct GuiButton *gbtn); void gui_go_to_event(struct GuiButton *gbtn); @@ -375,6 +377,7 @@ void frontend_ldcampaign_change_state(struct GuiButton *gbtn); void frontend_netservice_change_state(struct GuiButton *gbtn); void frontend_start_new_game(struct GuiButton *gbtn); void frontend_load_mappacks(struct GuiButton *gbtn); +void frontend_load_mp_mappacks(struct GuiButton *gbtn); void frontend_load_continue_game(struct GuiButton *gbtn); short frontend_save_continue_game(short allow_lvnum_grow); void frontend_continue_game_maintain(struct GuiButton *gbtn); diff --git a/src/frontmenu_net_data.cpp b/src/frontmenu_net_data.cpp index 462ebc43f0..8516aa7f81 100644 --- a/src/frontmenu_net_data.cpp +++ b/src/frontmenu_net_data.cpp @@ -114,8 +114,14 @@ struct GuiButtonInit frontend_net_start_buttons[] = { { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, frontnet_select_alliance,NULL,frontend_over_button, 1, 453, 186, 453, 186, 22, 26, frontnet_draw_alliance_button, 0, GUIStr_Empty, 0, {77}, 0, frontnet_maintain_alliance }, { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, frontnet_select_alliance,NULL,frontend_over_button, 2, 475, 186, 475, 186, 22, 26, frontnet_draw_alliance_button, 0, GUIStr_Empty, 0, {77}, 0, frontnet_maintain_alliance }, { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, frontnet_select_alliance,NULL,frontend_over_button, 3, 497, 186, 497, 186, 22, 26, frontnet_draw_alliance_button, 0, GUIStr_Empty, 0, {77}, 0, frontnet_maintain_alliance }, - { LbBtnT_HoldableBtn,BID_DEFAULT, 0, 0, NULL, NULL, NULL, 0, 284, 217, 284, 217, 240, 26, frontnet_draw_bottom_scroll_box_tab,0,GUIStr_Empty, 0, {28}, 0, NULL }, - { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, frontend_toggle_computer_players,NULL,frontend_over_button,0,297,214,297,214,220,26, frontend_draw_computer_players, 0, GUIStr_Empty, 0, {103}, 0, NULL }, + + { LbBtnT_HoldableBtn,BID_DEFAULT, 0, 0, NULL, NULL, NULL, 0,305,217,305,217,220,26, frontnet_draw_bottom_scroll_box_tab,0,GUIStr_Empty, 0, {28}, 0, NULL }, + { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, frontend_toggle_computer_players,NULL,frontend_over_button,0,315,214,315,214,200,26, frontend_draw_computer_players, 0, GUIStr_Empty, 0, {103}, 0, NULL }, + + + { LbBtnT_HoldableBtn,BID_DEFAULT, 0, 0, NULL, NULL, NULL, 0, 85,217,85,217, 220, 26, frontnet_draw_bottom_scroll_box_tab,0,GUIStr_Empty, 0, {28}, 0, NULL }, //pack select background + { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, frontend_load_mp_mappacks,NULL,frontend_over_button,0, 95,214,95,214, 200, 26, frontend_draw_mp_mappack, 0,GUIStr_Empty, 0, {100}, 0, NULL }, //pack select + { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, NULL, NULL, NULL, 0, 82, 246, 82, 246, 220, 26, frontnet_draw_scroll_box_tab, 0, GUIStr_Empty, 0, {28}, 0, NULL }, { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, NULL, NULL, NULL, 0, 82, 272, 82, 272, 450,111, frontnet_draw_scroll_box, 0, GUIStr_Empty, 0, {91}, 0, NULL }, { LbBtnT_HoldableBtn,BID_DEFAULT, 0, 0, frontnet_messages_up,NULL, frontend_over_button, 0, 532, 271, 532, 271, 26, 14, frontnet_draw_slider_button, 0, GUIStr_Empty, 0, {38}, 0, frontnet_messages_up_maintain }, diff --git a/src/frontmenu_select.c b/src/frontmenu_select.c index 3aa37f379f..4505f3f520 100644 --- a/src/frontmenu_select.c +++ b/src/frontmenu_select.c @@ -32,6 +32,7 @@ #include "player_data.h" #include "packets.h" #include "frontend.h" +#include "front_network.h" #include "game_legacy.h" #include "kjm_input.h" #include "keeperfx.hpp" @@ -42,10 +43,12 @@ int select_level_scroll_offset = 0; int select_campaign_scroll_offset = 0; int select_mappack_scroll_offset = 0; +int select_mp_mappack_scroll_offset = 0; int number_of_freeplay_levels = 0; int frontend_select_level_items_visible = 0; int frontend_select_campaign_items_visible = 0; int frontend_select_mappack_items_visible = 0; +int frontend_select_mp_mappack_items_visible = 0; /******************************************************************************/ void frontend_level_select_up(struct GuiButton *gbtn) { @@ -407,6 +410,129 @@ void frontend_mappack_select(struct GuiButton *gbtn) frontend_set_state(FeSt_LEVEL_SELECT); } + + + + + + + + +void frontend_mp_mappack_list_load(void) +{ + select_level_scroll_offset = 0; // Reset the scroll of the level select screen here, as it should only be reset when user returns to map pack select screen (Not from exiting level etc). + frontend_select_mp_mappack_items_visible = (mp_mappacks_list.items_num < frontend_select_mp_mappack_items_max_visible)?mp_mappacks_list.items_num+1:frontend_select_mp_mappack_items_max_visible; +} + +void frontend_mp_mappack_select_up(struct GuiButton *gbtn) +{ + if (select_mp_mappack_scroll_offset > 0) + select_mp_mappack_scroll_offset--; +} + +void frontend_mp_mappack_select_down(struct GuiButton *gbtn) +{ + if (select_mp_mappack_scroll_offset < mp_mappacks_list.items_num-frontend_select_mp_mappack_items_visible+1) + select_mp_mappack_scroll_offset++; +} + +void frontend_mp_mappack_select_scroll(struct GuiButton *gbtn) +{ + select_mp_mappack_scroll_offset = frontend_scroll_tab_to_offset(gbtn, GetMouseY(), frontend_select_mp_mappack_items_visible-2, mp_mappacks_list.items_num); +} + +void frontend_mp_mappack_select_up_maintain(struct GuiButton *gbtn) +{ + if (gbtn == NULL) + return; + if (select_mp_mappack_scroll_offset != 0) + gbtn->flags |= LbBtnF_Enabled; + else + gbtn->flags &= ~LbBtnF_Enabled; +} + +void frontend_mp_mappack_select_down_maintain(struct GuiButton *gbtn) +{ + if (gbtn == NULL) + return; + if (select_mp_mappack_scroll_offset < mp_mappacks_list.items_num-frontend_select_mp_mappack_items_visible+1) + gbtn->flags |= LbBtnF_Enabled; + else + gbtn->flags &= ~LbBtnF_Enabled; +} + +void frontend_mp_mappack_select_maintain(struct GuiButton *gbtn) +{ + if (gbtn == NULL) + return; + long btn_idx = gbtn->content.lval; + long i = select_mp_mappack_scroll_offset + btn_idx - 45; + if (i < mp_mappacks_list.items_num) + gbtn->flags |= LbBtnF_Enabled; + else + gbtn->flags &= ~LbBtnF_Enabled; +} + +void frontend_mp_mappack_select(struct GuiButton *gbtn) +{ + long i; + long btn_idx; + struct GameCampaign *campgn; + if (gbtn == NULL) + return; + btn_idx = gbtn->content.lval; + i = select_mp_mappack_scroll_offset + btn_idx-45; + campgn = NULL; + if ((i >= 0) && (i < mp_mappacks_list.items_num)) + campgn = &mp_mappacks_list.items[i]; + if (campgn == NULL) + return; + + // Send campaign change message to other players + char base_name[64]; + strncpy(base_name, campgn->fname, sizeof(base_name)-1); + base_name[sizeof(base_name)-1] = '\0'; + char *dot = strrchr(base_name, '.'); + if (dot != NULL) *dot = '\0'; + + static char msg[64]; + snprintf(msg, sizeof(msg), "%s:_", base_name); + set_auto_message(msg); + + if (!change_campaign(campgn->fname)) + return; + frontend_set_state(FeSt_NET_START); +} + +void frontend_draw_mp_mappack_select_button(struct GuiButton *gbtn) +{ + struct GameCampaign *campgn; + long btn_idx; + long i; + if (gbtn == NULL) + return; + btn_idx = gbtn->content.lval; + i = select_mp_mappack_scroll_offset + btn_idx-45; + campgn = NULL; + if ((i >= 0) && (i < mp_mappacks_list.items_num)) + campgn = &mp_mappacks_list.items[i]; + if (campgn == NULL) + return; + if ((btn_idx > 0) && (frontend_mouse_over_button == btn_idx)) + i = 2; + else + i = 1; + + lbDisplay.DrawFlags = Lb_TEXT_HALIGN_LEFT; + LbTextSetFont(frontend_font[i]); + int tx_units_per_px; + // This text is a bit condensed - button size is smaller than text height + tx_units_per_px = (gbtn->height*13/11) * 16 / LbTextLineHeight(); + i = LbTextLineHeight() * tx_units_per_px / 16; + LbTextSetWindow(gbtn->scr_pos_x, gbtn->scr_pos_y, gbtn->width, i); + LbTextDrawResized(0, 0, tx_units_per_px, campgn->display_name); +} + void frontend_draw_mappack_select_button(struct GuiButton *gbtn) { struct GameCampaign *campgn; diff --git a/src/frontmenu_select.h b/src/frontmenu_select.h index a9f1865cc2..942e7910e9 100644 --- a/src/frontmenu_select.h +++ b/src/frontmenu_select.h @@ -38,6 +38,9 @@ extern struct GuiMenu frontend_select_level_menu; extern struct GuiMenu frontend_select_campaign_menu; #define frontend_select_mappack_items_max_visible 7 extern struct GuiMenu frontend_select_mappack_menu; +#define frontend_select_mp_mappack_items_max_visible 7 +extern struct GuiMenu frontend_select_mp_mappack_menu; + /******************************************************************************/ // Level list selection screen void frontend_draw_levels_scroll_tab(struct GuiButton *gbtn); @@ -75,11 +78,26 @@ void frontend_mappack_select_up_maintain(struct GuiButton *gbtn); void frontend_mappack_select_down_maintain(struct GuiButton *gbtn); void frontend_mappack_select_maintain(struct GuiButton *gbtn); void frontend_draw_mappack_select_button(struct GuiButton *gbtn); +void frontend_draw_mp_mappack_select_button(struct GuiButton *gbtn); void frontend_mappack_select(struct GuiButton *gbtn); void frontend_mappack_select_update(void); void frontend_draw_mappack_scroll_tab(struct GuiButton *gbtn); void frontend_mappack_list_load(void); void frontend_draw_variable_mappack_exit_button(struct GuiButton *gbtn); + +// Multiplayer Map pack selection screen +void frontend_mp_mappack_select_up(struct GuiButton *gbtn); +void frontend_mp_mappack_select_down(struct GuiButton *gbtn); +void frontend_mp_mappack_select_scroll(struct GuiButton *gbtn); +void frontend_mp_mappack_select_up_maintain(struct GuiButton *gbtn); +void frontend_mp_mappack_select_down_maintain(struct GuiButton *gbtn); +void frontend_mp_mappack_select_maintain(struct GuiButton *gbtn); +void frontend_mp_draw_mappack_select_button(struct GuiButton *gbtn); +void frontend_mp_mappack_select(struct GuiButton *gbtn); +void frontend_mp_mappack_select_update(void); +void frontend_mp_draw_mappack_scroll_tab(struct GuiButton *gbtn); +void frontend_mp_mappack_list_load(void); +void frontend_mp_draw_variable_mappack_exit_button(struct GuiButton *gbtn); /******************************************************************************/ #ifdef __cplusplus } diff --git a/src/frontmenu_select_data.cpp b/src/frontmenu_select_data.cpp index bde0ae43da..f3e37e8443 100644 --- a/src/frontmenu_select_data.cpp +++ b/src/frontmenu_select_data.cpp @@ -96,13 +96,36 @@ struct GuiButtonInit frontend_select_mappack_buttons[] = { {-1, BID_DEFAULT, 0, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, NULL, 0, GUIStr_Empty, 0, {0}, 0, NULL }, }; +struct GuiButtonInit frontend_select_mp_mappack_buttons[] = { + { LbBtnT_NormalBtn, BID_MENU_TITLE, 0, 0, NULL, NULL, NULL, 0, 999, 30, 999, 30,371, 46, frontend_draw_large_menu_button, 0, GUIStr_Empty, 0, {100}, 0, NULL}, + { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, NULL, NULL, NULL, 0, 82, 128, 82, 128,220, 26, frontend_draw_scroll_box_tab, 0, GUIStr_Empty, 0, {28}, 0, NULL}, + { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, NULL, NULL, NULL, 0, 82, 154, 82, 154,450,180, frontend_draw_scroll_box, 0, GUIStr_Empty, 0, {26}, 0, NULL}, + { LbBtnT_HoldableBtn,BID_DEFAULT, 0, 0, frontend_mp_mappack_select_up,NULL,frontend_over_button, 0, 532, 153, 532, 153, 26, 14, frontend_draw_slider_button, 0, GUIStr_Empty, 0, {17}, 0, frontend_mp_mappack_select_up_maintain}, + { LbBtnT_HoldableBtn,BID_DEFAULT, 0, 0, frontend_mp_mappack_select_down,NULL,frontend_over_button,0, 532, 321, 532, 321, 26, 14, frontend_draw_slider_button, 0, GUIStr_Empty, 0, {18}, 0, frontend_mp_mappack_select_down_maintain}, + { LbBtnT_HoldableBtn,BID_DEFAULT, 0, 0, frontend_mp_mappack_select_scroll,NULL,NULL, 0, 536, 167, 536, 167, 20,154, frontend_draw_mappack_scroll_tab, 0, GUIStr_Empty, 0, {40}, 0, NULL}, + { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, NULL, NULL, NULL, 0, 102, 129, 102, 129,220, 26, frontend_draw_text, 0, GUIStr_Empty, 0, {112}, 0, NULL}, + { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, frontend_mp_mappack_select,NULL,frontend_over_button, 0, 95, 167, 95, 169,424, 22, frontend_draw_mp_mappack_select_button,0,GUIStr_Empty, 0, {45}, 0, frontend_mp_mappack_select_maintain}, + { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, frontend_mp_mappack_select,NULL,frontend_over_button, 0, 95, 189, 95, 191,424, 22, frontend_draw_mp_mappack_select_button,0,GUIStr_Empty, 0, {46}, 0, frontend_mp_mappack_select_maintain}, + { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, frontend_mp_mappack_select,NULL,frontend_over_button, 0, 95, 211, 95, 213,424, 22, frontend_draw_mp_mappack_select_button,0,GUIStr_Empty, 0, {47}, 0, frontend_mp_mappack_select_maintain}, + { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, frontend_mp_mappack_select,NULL,frontend_over_button, 0, 95, 233, 95, 235,424, 22, frontend_draw_mp_mappack_select_button,0,GUIStr_Empty, 0, {48}, 0, frontend_mp_mappack_select_maintain}, + { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, frontend_mp_mappack_select,NULL,frontend_over_button, 0, 95, 255, 95, 257,424, 22, frontend_draw_mp_mappack_select_button,0,GUIStr_Empty, 0, {49}, 0, frontend_mp_mappack_select_maintain}, + { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, frontend_mp_mappack_select,NULL,frontend_over_button, 0, 95, 277, 95, 279,424, 22, frontend_draw_mp_mappack_select_button,0,GUIStr_Empty, 0, {50}, 0, frontend_mp_mappack_select_maintain}, + { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, frontend_mp_mappack_select,NULL,frontend_over_button, 0, 95, 299, 95, 301,424, 22, frontend_draw_mp_mappack_select_button,0,GUIStr_Empty, 0, {51}, 0, frontend_mp_mappack_select_maintain}, + { LbBtnT_NormalBtn, BID_DEFAULT, 0, 0, frontend_change_state,NULL,frontend_over_button, 1, 999, 404, 999, 404,371, 46, frontend_draw_large_menu_button, 0, GUIStr_Empty, 0, {6}, 0, NULL}, + {-1, BID_DEFAULT, 0, 0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, NULL, 0, GUIStr_Empty, 0, {0}, 0, NULL }, +}; + struct GuiMenu frontend_select_mappack_menu = { GMnu_MAPPACK_SELECT, 0, 1, frontend_select_mappack_buttons, POS_SCRCTR, POS_SCRCTR, 640, 480, NULL, 0, NULL, NULL, 0, 0, 0,}; struct GuiMenu frontend_select_level_menu = { GMnu_FELEVEL_SELECT, 0, 1, frontend_select_level_buttons, POS_SCRCTR, POS_SCRCTR, 640, 480, NULL, 0, NULL, NULL, 0, 0, 0,}; struct GuiMenu frontend_select_campaign_menu = { GMnu_FECAMPAIGN_SELECT, 0, 1, frontend_select_campaign_buttons,POS_SCRCTR, POS_SCRCTR, 640, 480, NULL, 0, NULL, NULL, 0, 0, 0,}; +struct GuiMenu frontend_select_mp_mappack_menu = + { GMnu_MP_MAPPACK_SELECT, 0, 1, frontend_select_mp_mappack_buttons, POS_SCRCTR, POS_SCRCTR, 640, 480, NULL, 0, NULL, NULL, 0, 0, 0,}; + + /******************************************************************************/ #ifdef __cplusplus } diff --git a/src/gui_frontmenu.h b/src/gui_frontmenu.h index a57c0087a5..d91de96e63 100644 --- a/src/gui_frontmenu.h +++ b/src/gui_frontmenu.h @@ -76,6 +76,7 @@ enum GUI_Menus { GMnu_SPELL2 = 46, GMnu_ROOM2 = 47, GMnu_TRAP2 = 48, + GMnu_MP_MAPPACK_SELECT = 49, }; #define MENU_INVALID_ID -1 diff --git a/src/main.cpp b/src/main.cpp index 508d3a7cf0..ab69a1cec2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -252,6 +252,7 @@ TbBool should_use_delta_time_on_menu() case FeSt_LEVEL_SELECT: case FeSt_CAMPAIGN_SELECT: case FeSt_MAPPACK_SELECT: + case FeSt_MP_MAPPACK_SELECT: case FeSt_LAND_VIEW: case FeSt_NETLAND_VIEW: case FeSt_TORTURE: @@ -3685,17 +3686,22 @@ static TbBool wait_at_frontend(void) } game.save_game_slot = -1; // Make sure campaigns are loaded - if (!load_campaigns_list()) + if (!load_campaigns_list(&campaigns_list ,FGrp_Campgn ,"campaigns","campgn_order.txt")) { ERRORLOG("No valid campaign files found"); exit_keeper = 1; return true; } // Make sure mappacks are loaded - if (!load_mappacks_list()) + if (!load_campaigns_list(&mappacks_list,FGrp_VarLevels,"mappacks","mappck_order.txt")) { WARNMSG("No valid mappack files found"); } + if (!load_campaigns_list(&mp_mappacks_list,FGrp_MpLevels,"multiplayer mappacks","mp_mappck_order.txt")) + { + WARNMSG("No valid multiplayer mappack files found"); + } + set_default_mp_mappack(); //Set level number and campaign (for single level mode: GOF_SingleLevel) if ((start_params.operation_flags & GOF_SingleLevel) != 0) { diff --git a/src/packets.c b/src/packets.c index fec82dfca2..8f44c35b36 100644 --- a/src/packets.c +++ b/src/packets.c @@ -1752,13 +1752,21 @@ TbBool try_starting_level_from_chat(char* message, long player_id) } char *level_str = separator_pos + 1; - if (!isdigit(level_str[0])) { + if (level_str[0] != '_' && !isdigit(level_str[0])) { return false; } - - LevelNumber level_num = atoi(level_str); - if (level_num <= 0) { - return false; + + LevelNumber level_num; + if (level_str[0] == '_') + { + level_num = -1; + } + else + { + level_num = atoi(level_str); + if (level_num <= 0) { + return false; + } } char campaign_filename[80]; @@ -1768,9 +1776,12 @@ TbBool try_starting_level_from_chat(char* message, long player_id) ERRORLOG("Unable to load campaign '%.*s' for level %d", campaign_len, message, (int)level_num); return false; } + + if (level_num != -1) { + set_selected_level_number(level_num); + frontend_set_state(FeSt_START_MPLEVEL); + } - set_selected_level_number(level_num); - frontend_set_state(FeSt_START_MPLEVEL); return true; }