From 4b8c6983e7fa6347e9ab66051fa5f10652554efe Mon Sep 17 00:00:00 2001 From: translators Date: Thu, 4 Feb 2016 18:45:36 +0000 Subject: [PATCH 01/15] (svn r27506) -Update from Eints: french: 13 changes by OliTTD --- src/lang/french.txt | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/lang/french.txt b/src/lang/french.txt index 8ecc2db4ed..dc97e8d3dd 100644 --- a/src/lang/french.txt +++ b/src/lang/french.txt @@ -167,7 +167,7 @@ STR_ABBREV_ALL :{TINY_FONT}ALL # 'Mode' of transport for cargoes STR_PASSENGERS :{COMMA}{NBSP}passager{P "" s} -STR_BAGS :{COMMA}{NBSP}sac{P "" s} +STR_BAGS :{COMMA}{NBSP}sac{P 0 "" s} STR_TONS :{COMMA}{NBSP}tonne{P "" s} STR_LITERS :{COMMA}{NBSP}litre{P "" s} STR_ITEMS :{COMMA}{NBSP}unité{P "" s} @@ -815,8 +815,8 @@ STR_PRESIDENT_NAME_MANAGER :{BLACK}{PRESIDE STR_NEWS_NEW_TOWN :{BLACK}{BIG_FONT}{STRING} a sponsorisé la construction de la nouvelle ville {TOWN}{NBSP}! -STR_NEWS_INDUSTRY_CONSTRUCTION :{BIG_FONT}{BLACK}Un{G "" "" e} nouv{G eau el elle} {STRING} en construction près de {TOWN}{NBSP}! -STR_NEWS_INDUSTRY_PLANTED :{BIG_FONT}{BLACK}Un{G "" "" e} nouv{G eau el elle} {STRING} s'implante près de {TOWN}{NBSP}! +STR_NEWS_INDUSTRY_CONSTRUCTION :{BIG_FONT}{BLACK}Un{G 0 "" "" e} nouv{G 0 eau el elle} {STRING} en construction près de {TOWN}{NBSP}! +STR_NEWS_INDUSTRY_PLANTED :{BIG_FONT}{BLACK}Un{G 0 "" "" e} nouv{G 0 eau el elle} {STRING} s'implante près de {TOWN}{NBSP}! STR_NEWS_INDUSTRY_CLOSURE_GENERAL :{BIG_FONT}{BLACK}{STRING} annonce une fermeture imminente{NBSP}! STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS :{BIG_FONT}{BLACK}Des problèmes d'approvisionnement obligent {STRING} à fermer bientôt{NBSP}! @@ -858,9 +858,9 @@ STR_NEWS_AIRCRAFT_DEST_TOO_FAR :{WHITE}{VEHICLE STR_NEWS_ORDER_REFIT_FAILED :{WHITE}L'échec du réaménagement a stoppé {VEHICLE} STR_NEWS_VEHICLE_AUTORENEW_FAILED :{WHITE}Le renouvellement automatique de {VEHICLE} a échoué{}{STRING} -STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE :{BIG_FONT}{BLACK}Nouv{G eau el elle} {STRING} disponible{NBSP}! +STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE :{BIG_FONT}{BLACK}Nouv{G 0 eau el elle} {STRING} disponible{NBSP}! STR_NEWS_NEW_VEHICLE_TYPE :{BIG_FONT}{BLACK}{ENGINE} -STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE :{BLACK}Nouv{G eau el elle} {STRING} disponible{NBSP}! - {ENGINE} +STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE :{BLACK}Nouv{G 0 eau el elle} {STRING} disponible{NBSP}! - {ENGINE} STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO :{WHITE}{STATION} n'accepte plus {STRING} STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_OR_CARGO :{WHITE}{STATION} n'accepte plus {STRING} ou {STRING} @@ -1215,8 +1215,8 @@ STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :à droite de la STR_CONFIG_SETTING_SHOWFINANCES :Afficher le bilan financier en fin d'année{NBSP}: {STRING} STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :Si activé, le bilan financier sera affiché à la fin de chaque année pour permettre un contrôle rapide de l'état de la compagnie. STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :Les nouveaux ordres sont « sans arrêt » par défaut{NBSP}: {STRING} -STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT :Normalement, un véhicule s'arrête dans chaque station qu'il traverse. En activant ce paramètre, il traversera toutes les stations sur le chemin de sa destination finale sans s'arrêter. Noter que ce paramètre défini uniquement une valeur par défaut pour les nouveaux ordres. Les ordres peuvent par ailleurs être réglés individuellement avec un autre comportement -STR_CONFIG_SETTING_STOP_LOCATION :Les nouveaux ordres arrêtent les trains {G 0:2 au au "à la"} {STRING} du quai par défaut +STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT :Normalement, un véhicule s'arrête dans chaque station qu'il traverse. En activant ce paramètre, il traversera toutes les stations sur le chemin de sa destination finale sans s'arrêter. Noter que ce paramètre définit uniquement une valeur par défaut pour les nouveaux ordres. Les ordres peuvent par après être réglés individuellement avec un autre comportement +STR_CONFIG_SETTING_STOP_LOCATION :Les nouveaux ordres arrêtent les trains {G 0 au au "à la"} {STRING} du quai par défaut STR_CONFIG_SETTING_STOP_LOCATION_HELPTEXT :Endroit du quai où un train s'arrête par défaut. "queue" signifie proche du point d'entrée. "milieu" signifie au milieu du quai. "tête" signifie à l'opposé du point d'entrée. Noter que ce paramètre défini uniquement une valeur par défaut pour les nouveaux ordres. Les ordres peuvent par ailleurs être réglés individuellement avec un autre comportement STR_CONFIG_SETTING_STOP_LOCATION_NEAR_END :{G=f}queue STR_CONFIG_SETTING_STOP_LOCATION_MIDDLE :{G=m}milieu @@ -1407,7 +1407,7 @@ STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_FIRST :Premier disponi STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_LAST :Dernier disponible STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_MOST_USED :Le plus utilisé STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION :Afficher les réservations de chemin sur les voies{NBSP}: {STRING} -STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION_HELPTEXT :Donne une couleur différente aux voies réservées pour aider à résoudre les problèmes de trains refusant d'entrer dans des blocs basés sur le chemin +STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION_HELPTEXT :Donne une couleur différente aux voies réservées afin d'aider à résoudre les problèmes de trains refusant de s'engager dans des tronçons encadrés par des signaux de passage STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS :Conserver les outils de construction actifs après usage{NBSP}: {STRING} STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS_HELPTEXT :Garde les outils de construction de ponts, tunnels, etc. ouverts après usage STR_CONFIG_SETTING_EXPENSES_LAYOUT :Regrouper les dépenses dans la fenêtre des finances{NBSP}: {STRING} @@ -1464,15 +1464,15 @@ STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Nombre maximum STR_CONFIG_SETTING_SERVINT_ISPERCENT :Les intervalles de service sont en pourcentage{NBSP}: {STRING} STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :Choisir si l'entretien des véhicule est activé par le temps passé depuis le dernier entretien ou par la fiabilité passant sous un pourcentage de la fiabilité maximum STR_CONFIG_SETTING_SERVINT_TRAINS :Intervalle d'entretien par défaut pour les trains{NBSP}: {STRING} -STR_CONFIG_SETTING_SERVINT_TRAINS_HELPTEXT :Défini l'intervalle d'entretien par défaut des nouveaux véhicules ferroviaires, si aucun intervalle d'entretien n'est définit pour le véhicule +STR_CONFIG_SETTING_SERVINT_TRAINS_HELPTEXT :Définit l'intervalle d'entretien par défaut des nouveaux véhicules ferroviaires, si aucun intervalle d'entretien n'est défini pour le véhicule STR_CONFIG_SETTING_SERVINT_VALUE :{COMMA}{NBSP}jour{P 0 "" s}/% STR_CONFIG_SETTING_SERVINT_DISABLED :Désactivé STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES :Intervalle d'entretien par défaut pour les véhicules routiers{NBSP}: {STRING} -STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES_HELPTEXT :Défini l'intervalle d'entretien par défaut des nouveaux véhicules routiers, si aucun intervalle d'entretien n'est définit pour le véhicule +STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES_HELPTEXT :Définit l'intervalle d'entretien par défaut des nouveaux véhicules routiers, si aucun intervalle d'entretien n'est défini pour le véhicule STR_CONFIG_SETTING_SERVINT_AIRCRAFT :Intervalle d'entretien par défaut pour les aéronefs{NBSP}: {STRING} -STR_CONFIG_SETTING_SERVINT_AIRCRAFT_HELPTEXT :Défini l'intervalle d'entretien par défaut des nouveaux aéronefs, si aucun intervalle d'entretien n'est définit pour le véhicule +STR_CONFIG_SETTING_SERVINT_AIRCRAFT_HELPTEXT :Définit l'intervalle d'entretien par défaut des nouveaux aéronefs, si aucun intervalle d'entretien n'est défini pour le véhicule STR_CONFIG_SETTING_SERVINT_SHIPS :Intervalle d'entretien par défaut pour les navires{NBSP}: {STRING} -STR_CONFIG_SETTING_SERVINT_SHIPS_HELPTEXT :Défini l'intervalle d'entretien par défaut des nouveaux navires, si aucun intervalle d'entretien n'est définit pour le véhicule +STR_CONFIG_SETTING_SERVINT_SHIPS_HELPTEXT :Définit l'intervalle d'entretien par défaut des nouveaux navires, si aucun intervalle d'entretien n'est défini pour le véhicule STR_CONFIG_SETTING_NOSERVICE :Désactiver l'entretien quand les pannes sont inactives{NBSP}: {STRING} STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :Lorsqu'il est activé, les véhicules ne sont pas entretenus s'ils ne peuvent pas tomber en panne STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Activer la vitesse limite des wagons{NBSP}: {STRING} @@ -2221,7 +2221,7 @@ STR_CONTENT_DETAIL_SUBTITLE_SELECTED :{SILVER}Pré-s STR_CONTENT_DETAIL_SUBTITLE_AUTOSELECTED :{SILVER}Cette dépendance a été sélectionnée pour être téléchargée STR_CONTENT_DETAIL_SUBTITLE_ALREADY_HERE :{SILVER}Vous avez déjà ceci STR_CONTENT_DETAIL_SUBTITLE_DOES_NOT_EXIST :{SILVER}Ce module est inconnu et ne peut pas être téléchargé dans OpenTTD -STR_CONTENT_DETAIL_UPDATE :{SILVER}Ceci est un remplacement pour {G "un" "des" "une"} {STRING} existant{G 0 "" "s" "e"} +STR_CONTENT_DETAIL_UPDATE :{SILVER}Ceci est un remplacement pour {G 0 "un" "des" "une"} {STRING} existant{G 0 "" "s" "e"} STR_CONTENT_DETAIL_NAME :{SILVER}Nom{NBSP}: {WHITE}{STRING} STR_CONTENT_DETAIL_VERSION :{SILVER}Version{NBSP}: {WHITE}{STRING} STR_CONTENT_DETAIL_DESCRIPTION :{SILVER}Description{NBSP}: {WHITE}{STRING} From 9db36bd87ae8c0258a8d2dff1733ddfe65ad9c4f Mon Sep 17 00:00:00 2001 From: frosch Date: Mon, 8 Feb 2016 21:05:57 +0000 Subject: [PATCH 02/15] (svn r27507) -Add: [NewGRF] Allow custom sound IDs in RV property 0x12, ship property 0x10 and aircraft property 0x12. --- src/newgrf.cpp | 6 +++--- src/newgrf_sound.cpp | 33 +++++++++++++++++++++------------ src/newgrf_sound.h | 1 + src/sound_type.h | 2 ++ 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/newgrf.cpp b/src/newgrf.cpp index cf45608b63..b9c1bf89e3 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -1402,7 +1402,7 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop break; case 0x12: // SFX - rvi->sfx = buf->ReadByte(); + rvi->sfx = GetNewGRFSoundID(_cur.grffile, buf->ReadByte()); break; case PROP_ROADVEH_POWER: // Power in units of 10 HP. @@ -1590,7 +1590,7 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop break; case 0x10: // SFX - svi->sfx = buf->ReadByte(); + svi->sfx = GetNewGRFSoundID(_cur.grffile, buf->ReadByte()); break; case 0x11: { // Cargoes available for refitting @@ -1758,7 +1758,7 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int break; case 0x12: // SFX - avi->sfx = buf->ReadByte(); + avi->sfx = GetNewGRFSoundID(_cur.grffile, buf->ReadByte()); break; case 0x13: { // Cargoes available for refitting diff --git a/src/newgrf_sound.cpp b/src/newgrf_sound.cpp index 60ee609165..0cc113d9df 100644 --- a/src/newgrf_sound.cpp +++ b/src/newgrf_sound.cpp @@ -161,6 +161,22 @@ bool LoadNewGRFSound(SoundEntry *sound) return false; } +/** + * Resolve NewGRF sound ID. + * @param file NewGRF to get sound from. + * @param sound_id GRF-specific sound ID. (GRF-local for IDs above ORIGINAL_SAMPLE_COUNT) + * @return Translated (global) sound ID, or INVALID_SOUND. + */ +SoundID GetNewGRFSoundID(const GRFFile *file, SoundID sound_id) +{ + /* Global sound? */ + if (sound_id < ORIGINAL_SAMPLE_COUNT) return sound_id; + + sound_id -= ORIGINAL_SAMPLE_COUNT; + if (file == NULL || sound_id >= file->num_sounds) return INVALID_SOUND; + + return file->sound_offset + sound_id; +} /** * Checks whether a NewGRF wants to play a different vehicle sound effect. @@ -185,14 +201,10 @@ bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event) /* Play default sound if callback fails */ if (callback == CALLBACK_FAILED) return false; - if (callback >= ORIGINAL_SAMPLE_COUNT) { - callback -= ORIGINAL_SAMPLE_COUNT; + callback = GetNewGRFSoundID(file, callback); - /* Play no sound if result is out of range */ - if (callback > file->num_sounds) return true; - - callback += file->sound_offset; - } + /* Play no sound, if result is invalid */ + if (callback == INVALID_SOUND) return true; assert(callback < GetNumSounds()); SndPlayVehicleFx(callback, v); @@ -207,11 +219,8 @@ bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event) */ void PlayTileSound(const GRFFile *file, SoundID sound_id, TileIndex tile) { - if (sound_id >= ORIGINAL_SAMPLE_COUNT) { - sound_id -= ORIGINAL_SAMPLE_COUNT; - if (sound_id > file->num_sounds) return; - sound_id += file->sound_offset; - } + sound_id = GetNewGRFSoundID(file, sound_id); + if (sound_id == INVALID_SOUND) return; assert(sound_id < GetNumSounds()); SndPlayTileFx(sound_id, tile); diff --git a/src/newgrf_sound.h b/src/newgrf_sound.h index 0d32953274..efded063c8 100644 --- a/src/newgrf_sound.h +++ b/src/newgrf_sound.h @@ -33,6 +33,7 @@ enum VehicleSoundEvent { SoundEntry *AllocateSound(uint num); void InitializeSoundPool(); bool LoadNewGRFSound(SoundEntry *sound); +SoundID GetNewGRFSoundID(const struct GRFFile *file, SoundID sound_id); SoundEntry *GetSound(SoundID sound_id); uint GetNumSounds(); bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event); diff --git a/src/sound_type.h b/src/sound_type.h index 72486dcac9..76fe25139e 100644 --- a/src/sound_type.h +++ b/src/sound_type.h @@ -119,4 +119,6 @@ static const uint ORIGINAL_SAMPLE_COUNT = 73; typedef uint16 SoundID; +static const SoundID INVALID_SOUND = 0xFFFF; + #endif /* SOUND_TYPE_H */ From 9043cbf9bf5125293a7205637fcac0771e239daa Mon Sep 17 00:00:00 2001 From: translators Date: Sat, 13 Feb 2016 18:45:36 +0000 Subject: [PATCH 03/15] (svn r27508) -Update from Eints: german: 1 change by mini1025 --- src/lang/german.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lang/german.txt b/src/lang/german.txt index ac0dbe7e11..eb1f501e06 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -2876,6 +2876,7 @@ STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Vorherig STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Gehe zum vorherigen normalen Sprite und überspringe alle Pseudo-, Recolour- und Schriftsprites (springt ggf. vom letzten bis zum ersten Sprite) STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Darstellung des aktuellen Sprites. Die Ausrichtung wird beim Zeichnen des Sprites ignoriert STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Bewege die Sprites und ändere dadurch die X- und Y-Offsets. Drücke Strg+Click um die Sprites 8 Blöcke weit zu bewegen. +STR_SPRITE_ALIGNER_RESET_BUTTON :{BLACK}Setze zurück STR_SPRITE_ALIGNER_RESET_TOOLTIP :{BLACK}Setze die aktuelle Verschiebung zurück. STR_SPRITE_ALIGNER_OFFSETS_ABS :{BLACK}X offset: {NUM}, Y offset: {NUM} (Absolut) STR_SPRITE_ALIGNER_OFFSETS_REL :{BLACK}X offset: {NUM}, Y offset: {NUM} (Relativ) From 769462f5371d9ab17ea1e7923f8c67ae74090f61 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 13 Feb 2016 19:26:47 +0000 Subject: [PATCH 04/15] Squashed commit of the following: commit b17f39a2016dc11a6a9815f398d690d82a6a59aa Merge: 67b3190 3bb7c47 Author: Thomas Schmidt Date: Fri Feb 12 19:44:34 2016 +0100 Merge branch 'merge/trunk27506' into dev commit 3bb7c4768580198b7316bfeebc4b870d355439e8 Merge: 14929fe 9db36bd Author: Thomas Schmidt Date: Fri Feb 12 19:43:53 2016 +0100 Merge remote-tracking branch 'openttd/master' into merge/trunk27506 commit 14929fe3536e2aa5b4d6a43d0d55043da7a2f252 Merge: af15609 4b8c698 Author: Thomas Schmidt Date: Wed Feb 10 22:14:25 2016 +0100 Merge branch 'master' into merge/trunk27506 commit 67b319060b4b88b72c94b0e0c2c9fdcf1c2fd95d Author: Thomas Schmidt Date: Sat Feb 28 20:17:13 2015 +0100 removed 2 unused function calls commit af15609c938eb388dd507b16fb7b6d547c54c2da Merge: 5465c88 b251ba3 Author: Thomas Schmidt Date: Sat Feb 28 15:12:33 2015 +0100 Merge branch 'trunk' into merge_trunk commit 5465c88c8016c5e7910570ab5795222e8348c703 Author: me Date: Sat Feb 28 10:59:41 2015 +0100 regenerated MSVS project files forgot to do this, they still retained the old filenames commit 0391455e29c5ed794fcd0f58c63ff98dc52685ac Author: Thomas Schmidt Date: Thu Feb 26 16:53:05 2015 +0100 removed the patch files from this repo again that was a rather dum idea, it made the difference patch between branches trunk and tbtr huge. the patch files are now being tracked again in the supplimentary repo 'tbtr_proj', that will keep this fork clean and creating diff-patches will be much easier commit 8395d40386c8d620c90fb4be66cf6679408ac975 Author: Thomas Schmidt Date: Thu Feb 26 16:27:40 2015 +0100 fix for reported bug by DC-1: crash in station gui the template gui item was added to the drop-down list that was also shown in a station gui, but there was no action present when this item was selected in a station gui. per default the game would commit suicide by called NOT_REACHED() at the default case of the according switch-statement. commit 833873245d33bd77105a82a584d9bec2362419bc Merge: 39596be 8688c95 Author: Thomas Schmidt Date: Thu Feb 26 15:08:53 2015 +0100 Merge branch 'fix_disableTemplateOrderCheck' into tbtr commit 8688c95a01ed5933a35a08597bbf45ff148f5a67 Author: Thomas Schmidt Date: Thu Feb 26 15:06:25 2015 +0100 added fix by DC-1 don't check the orders list of a virtual vehicle commit 39596beff9a815a0f9b2ea3abe5d82c3ec5933e7 Author: Thomas Schmidt Date: Sun Feb 22 10:47:58 2015 +0100 added history of patches for the mod commit b3ae74ac4e9143202a1fda1333a91c3716ebb21e Merge: 9a601a1 ee756e1 Author: Thomas Schmidt Date: Sun Feb 22 10:03:04 2015 +0100 Merge branch 'tbtr' into merge_tbtr commit ee756e1c2229534f1cc05edb97269b0c83ddde66 Author: Thomas Schmidt Date: Tue Feb 17 22:25:50 2015 +0100 removed nonsensical comments + disabled code commit e7d37f0500c56c84a36ce8b93eafb31f800e1086 Author: Thomas Schmidt Date: Tue Feb 17 21:30:38 2015 +0100 added some missing renames in includes commit 63c2b13766b077e4f2923f321e95d53356dee2db Merge: e92e6ba 9752606 Author: Thomas Schmidt Date: Tue Feb 17 21:22:11 2015 +0100 Merge branch 'feat_renameFiles' into merge_renameFiles Conflicts: src/tbtr_template_gui_create_virtualtrain.cpp commit 975260643d212f8cac72485f2011011210622849 Author: Thomas Schmidt Date: Mon Feb 9 22:11:18 2015 +0100 replaced source file prefix: aaa -> tbtr commit e92e6ba7089564886d17dd5c1fd8d85ea0ca4ac7 Merge: 62d2f80 ac16eab Author: Thomas Schmidt Date: Sun Feb 8 15:02:19 2015 +0100 Merge branch 'rm_TODOs' into dev Conflicts: src/aaa_template_gui_main.cpp commit 62d2f809edf170cfbeb0599822c4c3d4f9a1fefe Author: Thomas Schmidt Date: Sun Feb 8 14:59:36 2015 +0100 i++ -> ++i commit ac16eabc082f62b9fe2ef6c11a314f8e9a28c26b Author: Thomas Schmidt Date: Sun Feb 8 14:34:36 2015 +0100 rm'ed TODOs commit 22f642f32265882b8f99b409b517823991c08101 Author: Thomas Schmidt Date: Sun Feb 8 14:17:49 2015 +0100 rm TODO yes, depends on the selected template because the button "Start replacing" means, to start the replacement for the currently selected group and template (create a templatereplacement object for this combination) commit 60d8192838e340a3cf6899979361c997df73b716 Author: Thomas Schmidt Date: Sun Feb 8 14:17:26 2015 +0100 rm'ed TODO: included task in TODO-list commit 39e42674ac9f5ad5dd056b613e80ef4e754c1153 Author: Thomas Schmidt Date: Sun Feb 8 11:19:36 2015 +0100 changed window class in use: WC_NONE -> WC_TEMPLATE_GUI_MAIN commit cadfac96e21aeb862b75e0454197ddce89fb728c Author: Thomas Schmidt Date: Mon Jan 26 23:18:29 2015 +0100 removed a weird call to deleteAllTmplReplacements was a TODO task, it was set to delete all template replacements belonging to group with id -1, which does not exist, ever commit dc1058464c29f61b6197dec556ec468d1ff38451 Author: Thomas Schmidt Date: Sun Jan 25 23:27:03 2015 +0100 removed some TODOs commit 7afeb17db512600424039099a0f4bd78882fcd8e Author: Thomas Schmidt Date: Sun Jan 25 11:35:47 2015 +0100 removed all MYGUI comments tried to replace them with useful comments where necessary added a few new TODOs here and there commit 6b9453224a77811062254e6bce7dac4074b829a8 Merge: 292a5aa 687bc4c Author: Thomas Schmidt Date: Sun Jan 18 20:47:06 2015 +0100 Merge branch 'fix_compiler_warnings' into dev commit 687bc4c34fbb9ddeaf15b4857b235a9709dd85be Author: Thomas Schmidt Date: Sun Jan 18 20:43:26 2015 +0100 fixed all remaining warnings commit ada08d7097772e325b7852fd058d8bad7036ae4d Author: Thomas Schmidt Date: Sun Jan 18 18:25:45 2015 +0100 removed testing code that produced a warning commit f3b1568384f36998aeb1fa51c1fab4cfb96c7f93 Author: Thomas Schmidt Date: Sun Jan 18 00:07:34 2015 +0100 removed unused variable REPLACEMENT_IN_PROGRESS commit 5aa9098880070cfaa3d2815f445497b2886933f9 Author: Thomas Schmidt Date: Sun Jan 18 00:02:43 2015 +0100 removed variable 'mode' from ClickedOnVehicle() member function of class TemplateCreateWindow in the depot gui the mode variable is used to decide whether a vehicle is started or dragged or ... here, we only drag so the mode is never used commit 292a5aa9dba9cf1d0003e84055fb95357f922454 Merge: 8f6df8c 2bb12bc Author: Thomas Schmidt Date: Wed Jan 14 23:41:29 2015 +0100 Merge branch 'feat_mergePatch0.4c' into dev commit 2bb12bcf283cccc8869bf537b79b22f479cb7203 Author: Thomas Schmidt Date: Wed Jan 14 23:32:04 2015 +0100 added vi's .swp files to .gitignore commit aecf6f549b32f92342f8e0b65158bebef6270537 Author: Thomas Schmidt Date: Tue Jan 13 20:15:25 2015 +0100 corrected UpdateViewport code was VehicleUpdateViewport(Vehicle*, bool) before is Vehicle::UpdateViewport(bool, bool) now commit ae199283fd5ac0199cef1c4c980561122d030199 Author: Thomas Schmidt Date: Mon Jan 12 22:34:22 2015 +0100 updated code for EngineNumberSorter commit 9735035c6dd4ded9bb76958722dc25e26ced5f05 Author: Thomas Schmidt Date: Sun Jan 11 18:36:17 2015 +0100 removed unused parameter 'part_of_chain' from cargo movement code commit b8b86e1f2592288ddcfb46a0a5d81c3257da60d3 Author: Thomas Schmidt Date: Sun Jan 4 21:44:17 2015 +0100 Reimplemented moving of cargo - uses the new shift function - manages to spread the old cargo of replaced vehicles from a chain across the memebers of the newly constructed chain some TODOs are left within the code and some testing needs to be done, how this behaves when there is more than one vehicle being replaced commit 0d76e1bfe10ef207ac5e4018976e9fba0b0bb25e Author: Thomas Schmidt Date: Sat Jan 3 01:05:54 2015 +0100 fixed saveload code for TemplateVehicle commit ba0ea6975f48fe38c2b5376ebc83c23d6bb6151c Author: Thomas Schmidt Date: Fri Jan 2 11:32:23 2015 +0100 final changes for the merge - removed the WDF_UNLICK_BUTTON - updated ctor calls to Window() - disabled the engine number sorter commit 9cc213335046b3febfe6649fde40b00e1bb43d5b Author: Thomas Schmidt Date: Fri Jan 2 11:29:03 2015 +0100 disabled cargo movement during templrpl need to reimplement this step since the cargo is now moved packet-by-packet and not as a complete list from a vehicle onto another vehicle anymore commit 39743806d0156f8547670c525af0e59083dbcd49 Author: Thomas Schmidt Date: Fri Jan 2 11:16:54 2015 +0100 replaced cargo function 'Count' - not available anymore: VehicleCargoList::Count() - using StoredCount() for now, should check if this is the correct count commit 9b240bbf9b2ee5659bbcb518e9e2767103861254 Author: Thomas Schmidt Date: Fri Jan 2 01:27:56 2015 +0100 final corrections for template_gui_create_virtualtrain commit cf0d48d8fa052ff521e1fac0ec75d75107c9b76e Author: Thomas Schmidt Date: Fri Jan 2 01:20:30 2015 +0100 disbabled usage of not-anymore-existing newgrf_engine.h::ListPositionOfEngine commit 81da16b7f0c3ea2417b24707329d1d971a67e82e Author: Thomas Schmidt Date: Fri Jan 2 01:09:53 2015 +0100 fixed typo in value WID_BV_SORT_ASSENDING_DESCENDING commit c8f81a5c3df5ccf4858bda64a53979af510ccd87 Author: Thomas Schmidt Date: Fri Jan 2 01:09:25 2015 +0100 create_virtual_train: uint GetEngineListHeight not static commit bd29d99f80bd824e28104f3bc839fc2a5abdd297 Author: Thomas Schmidt Date: Fri Jan 2 00:57:25 2015 +0100 template_gui_create: static WindowDesc not const commit edee9c1c544845459102328209b98d424cfd3248 Author: Thomas Schmidt Date: Fri Jan 2 00:44:50 2015 +0100 updated call to Window::FinishInitNested commit 25fc3cb7ed6db15f42bd3fdff9506621fbba3d72 Author: Thomas Schmidt Date: Thu Jan 1 23:56:48 2015 +0100 updated ctor calls for classes derived from Window - first param in the constructor used to be const WindowDesc*, now it is WindowDesc* commit 54d710170f1ce9cf5539cd525744ca61f4089e7b Author: Thomas Schmidt Date: Thu Jan 1 02:50:29 2015 +0100 updated constr calls to WindowDesc::WindowDesc need a const char* at 2nd pos now commit 7c954141f00666dec4c9559019a1a4af3b452372 Author: Thomas Schmidt Date: Wed Dec 31 02:30:02 2014 +0100 applied patch vehicle.cpp commit aa12720049a3dfb1c2e02d453813bd567b67ff60 Author: Thomas Schmidt Date: Wed Dec 31 02:22:54 2014 +0100 applied patch vehicle_gui.cpp (failed hunks 2,4,5/6) commit 2b8e70f15478072264f1e063418f8de0744a98e1 Author: Thomas Schmidt Date: Wed Dec 31 02:13:29 2014 +0100 applied patch train_cmd.cpp (failed hunk 1/8) commit 47499523bf1ed0cce5fdf6cc2a7102e571dcb07d Author: Thomas Schmidt Date: Wed Dec 31 02:07:00 2014 +0100 applied patch newgrf_engine.cpp commit 7a40c62a7b5ab8059981270252a7def69eacb7d7 Author: Thomas Schmidt Date: Wed Dec 31 02:02:52 2014 +0100 applied patch vehicle_cmd.cpp (failed hunks 2,3/3) commit 277839abd8cb7eb277e4ed6cb72e0f3da5b7e479 Author: Thomas Schmidt Date: Wed Dec 31 01:56:35 2014 +0100 applied patch saveload.h (failed hunk 1/1) commit 7b64c87ad3dede6442a88dafa5aa8a6a3e0db812 Author: Thomas Schmidt Date: Wed Dec 31 01:53:56 2014 +0100 applied patch group_gui.cpp (failed hunks 2,3/4) commit 8075261c526004e21534fa0ab80429132d5f634b Author: Thomas Schmidt Date: Wed Dec 31 01:46:24 2014 +0100 applied patch vehiclelist.cpp (failed hunk 1/2) commit b1c197c0f38e45fb50dad7f7e33f1438b150a34f Author: Thomas Schmidt Date: Wed Dec 31 01:42:04 2014 +0100 applied patch train.h (failed hunk 1/3) commit 81bfa209e92fa74387420cc85851767d2737c1b0 Author: Thomas Schmidt Date: Tue Dec 30 01:43:10 2014 +0100 applied patch viewport.cpp.patch (file src/viewport.cpp) commit 5c083054544eabac9260a75033198c665b169215 Author: Thomas Schmidt Date: Tue Dec 30 01:43:10 2014 +0100 applied patch train_gui.cpp.patch (file src/train_gui.cpp) commit 3c3534621c6b37530035faadfa092d70fed724c9 Author: Thomas Schmidt Date: Tue Dec 30 01:43:10 2014 +0100 applied patch source.list.patch (file source.list) commit 6bbb071431882d4bab43023f7194f96c824e78e5 Author: Thomas Schmidt Date: Tue Dec 30 01:43:10 2014 +0100 applied patch saveload_internal.h.patch (file src/saveload/saveload_internal.h) commit 158640eb786cc7867c9e689eb8a92a209e528a83 Author: Thomas Schmidt Date: Tue Dec 30 01:43:10 2014 +0100 applied patch saveload.cpp.patch (file src/saveload/saveload.cpp) commit e171ad716c126e98bc045f5ce574ac6161f3ab4f Author: Thomas Schmidt Date: Tue Dec 30 01:43:10 2014 +0100 applied patch openttd_vs90.vcproj.patch (file projects/openttd_vs90.vcproj) commit b77486d89c12a80f73f088759da760abd0af7f49 Author: Thomas Schmidt Date: Tue Dec 30 01:43:10 2014 +0100 applied patch openttd_vs80.vcproj.patch (file projects/openttd_vs80.vcproj) commit 57f9c52fc580da51e20bd40f116fe66c9a0f3669 Author: Thomas Schmidt Date: Tue Dec 30 01:43:10 2014 +0100 applied patch openttd_vs100.vcxproj.patch (file projects/openttd_vs100.vcxproj) commit bda1f739a415600a7f522b1c7f9ca53fa7713ed3 Author: Thomas Schmidt Date: Tue Dec 30 01:43:10 2014 +0100 applied patch openttd_vs100.vcxproj.filters.patch (file projects/openttd_vs100.vcxproj.filters) commit ed96771b03e726e5cb56cac9a8328c3a1e63856b Author: Thomas Schmidt Date: Tue Dec 30 01:43:10 2014 +0100 applied patch newgrf_spritegroup.cpp.patch (file src/newgrf_spritegroup.cpp) commit 3df57e0d855fef5f54be4fd8d25e231a7eb3c3f1 Author: Thomas Schmidt Date: Tue Dec 30 01:43:10 2014 +0100 applied patch group_cmd.cpp.patch (file src/group_cmd.cpp) commit da31ca4b67d6993f127c6cecac717eb286ead4e6 Author: Thomas Schmidt Date: Tue Dec 30 01:43:09 2014 +0100 applied patch english.txt.patch (file src/lang/english.txt) commit ddc0af7139fccbae4060c70440f17c763e3bba96 Author: Thomas Schmidt Date: Tue Dec 30 01:43:09 2014 +0100 applied patch depot_gui.cpp.patch (file src/depot_gui.cpp) commit 88aca9db192c6a2b92185f56505caf8b91d23ab4 Author: Thomas Schmidt Date: Tue Dec 30 01:43:09 2014 +0100 applied patch autoreplace_cmd.cpp.patch (file src/autoreplace_cmd.cpp) commit 45ca80f7c9847ac3afe181a0badeb12bbbd5ed0d Author: Thomas Schmidt Date: Tue Dec 30 01:43:09 2014 +0100 applied patch articulated_vehicles.cpp.patch (file src/articulated_vehicles.cpp) commit 44bd0bf2e77f366b61f96b0f4ca564f2e2e5814a Author: Thomas Schmidt Date: Tue Dec 30 01:43:09 2014 +0100 applied patch afterload.cpp.patch (file src/saveload/afterload.cpp) commit 679f9b327f9d3f3bec327ae0266f289981972c85 Author: Thomas Schmidt Date: Tue Dec 30 01:43:09 2014 +0100 applied patch aaa_template_veh_sl.cpp.patch (file src/saveload/aaa_template_veh_sl.cpp) commit ebcec221ec7c1988e85ba458283ff362e034e6d5 Author: Thomas Schmidt Date: Tue Dec 30 01:43:09 2014 +0100 applied patch aaa_template_vehicle.h.patch (file src/aaa_template_vehicle.h) commit ad690e74b95d2aa07157b73834eef672c63ef901 Author: Thomas Schmidt Date: Tue Dec 30 01:43:09 2014 +0100 applied patch aaa_template_vehicle_func.h.patch (file src/aaa_template_vehicle_func.h) commit 5982153c369432fc694daaa91a06dfefeeb29485 Author: Thomas Schmidt Date: Tue Dec 30 01:43:09 2014 +0100 applied patch aaa_template_vehicle_func.cpp.patch (file src/aaa_template_vehicle_func.cpp) commit 773f889e165b013de96736fa380d5ab5c311b3dd Author: Thomas Schmidt Date: Tue Dec 30 01:43:09 2014 +0100 applied patch aaa_template_vehicle.cpp.patch (file src/aaa_template_vehicle.cpp) commit 03af781d69a09863d3b76ee4911e5eecd90a7cf5 Author: Thomas Schmidt Date: Tue Dec 30 01:43:09 2014 +0100 applied patch aaa_template_replacement_sl.cpp.patch (file src/saveload/aaa_template_replacement_sl.cpp) commit ab6cb0562fd390d551670dbc27e0c3c94c8554db Author: Thomas Schmidt Date: Tue Dec 30 01:43:09 2014 +0100 applied patch aaa_template_gui_replaceall.cpp.patch (file src/aaa_template_gui_replaceall.cpp) commit d88452a6195c55e39bceb3ea7689fc546c4eee6a Author: Thomas Schmidt Date: Tue Dec 30 01:43:09 2014 +0100 applied patch aaa_template_gui_main.cpp.patch (file src/aaa_template_gui_main.cpp) commit ab6ac687f355d400ad9ebc154e75477671a8e0fa Author: Thomas Schmidt Date: Tue Dec 30 01:42:21 2014 +0100 applied patch aaa_template_gui_create_virtualtrain.cpp.patch (file src/aaa_template_gui_create_virtualtrain.cpp) commit 288d14b9b145cb045b6a287d23cf3be4f2712ede Author: Thomas Schmidt Date: Tue Dec 30 01:38:12 2014 +0100 applied patch aaa_template_gui_create.cpp.patch (file src/aaa_template_gui_create.cpp) commit 5342db70e07fb7c1f3c41654abd2c6a4c51472c4 Author: Thomas Schmidt Date: Tue Dec 30 01:18:32 2014 +0100 applied aaa_* header files commit 6f14e94a0ad715a33a2653cf6c12e1c2981ace8d Author: Thomas Schmidt Date: Sun Dec 28 17:29:55 2014 +0100 applied vehicle_base.h.patch commit b76a5ce921fab5d81b60755ce66db71e38664e9b Author: Thomas Schmidt Date: Sun Dec 28 17:29:28 2014 +0100 applied window_type.h.patch commit d33d738c7e3477de3f12affcc74c88194a61c442 Author: Thomas Schmidt Date: Sun Dec 28 17:28:30 2014 +0100 applied newgrf_engine.h.patch commit 931fd1143706bc76aa145e1430645cb4496f9f4a Author: Thomas Schmidt Date: Sun Dec 28 17:27:21 2014 +0100 applied vehicle_gui.h.patch commit f6c4ab089dad5a4a01401e18cffa8f20e02f733e Author: Thomas Schmidt Date: Sun Dec 28 17:00:52 2014 +0100 applied vehicle_gui_base.h.patch commit 5f7378136758fcc4987791d264856169950cbfe2 Author: Thomas Schmidt Date: Sun Dec 28 12:34:23 2014 +0100 applied build_vehicle_widget.h.patch commit 5c6fc73847a2f34573260721bb68c7b552d546bc Author: Thomas Schmidt Date: Sun Dec 28 12:01:10 2014 +0100 applied autoreplace_func.h commit 7636f27011841d01e5f954c855dfa0cf1859e0e0 Author: Thomas Schmidt Date: Sun Dec 28 12:01:00 2014 +0100 applied newgrf.h Remove some spurious whitespace changes, update projects files. --- projects/openttd_vs100.vcxproj | 14 + projects/openttd_vs100.vcxproj.filters | 42 + projects/openttd_vs140.vcxproj | 14 + projects/openttd_vs140.vcxproj.filters | 42 + projects/openttd_vs80.vcproj | 56 ++ projects/openttd_vs90.vcproj | 56 ++ source.list | 15 + src/autoreplace_cmd.cpp | 2 +- src/autoreplace_func.h | 2 + src/group_cmd.cpp | 7 + src/group_gui.cpp | 8 + src/lang/english.txt | 59 ++ src/newgrf.h | 2 + src/order_cmd.cpp | 3 +- src/saveload/afterload.cpp | 3 + src/saveload/saveload.cpp | 11 + src/saveload/saveload.h | 1 + src/saveload/saveload_internal.h | 1 + src/saveload/tbtr_template_replacement_sl.cpp | 35 + src/saveload/tbtr_template_veh_sl.cpp | 99 +++ src/tbtr_template_gui_create.cpp | 459 ++++++++++ src/tbtr_template_gui_create.h | 11 + src/tbtr_template_gui_create_virtualtrain.cpp | 829 ++++++++++++++++++ src/tbtr_template_gui_create_virtualtrain.h | 8 + src/tbtr_template_gui_main.cpp | 692 +++++++++++++++ src/tbtr_template_gui_main.h | 20 + src/tbtr_template_gui_replaceall.cpp | 517 +++++++++++ src/tbtr_template_gui_replaceall.h | 27 + src/tbtr_template_vehicle.cpp | 227 +++++ src/tbtr_template_vehicle.h | 195 ++++ src/tbtr_template_vehicle_func.cpp | 773 ++++++++++++++++ src/tbtr_template_vehicle_func.h | 66 ++ src/train.h | 17 + src/train_cmd.cpp | 192 +++- src/vehicle.cpp | 44 +- src/vehicle_base.h | 4 + src/vehicle_cmd.cpp | 10 +- src/vehicle_gui.cpp | 18 +- src/vehicle_gui.h | 2 +- src/vehicle_gui_base.h | 1 + src/vehiclelist.cpp | 4 +- src/viewport.cpp | 3 +- src/widgets/build_vehicle_widget.h | 1 + src/window_type.h | 6 + 44 files changed, 4575 insertions(+), 23 deletions(-) create mode 100644 src/saveload/tbtr_template_replacement_sl.cpp create mode 100644 src/saveload/tbtr_template_veh_sl.cpp create mode 100644 src/tbtr_template_gui_create.cpp create mode 100644 src/tbtr_template_gui_create.h create mode 100644 src/tbtr_template_gui_create_virtualtrain.cpp create mode 100644 src/tbtr_template_gui_create_virtualtrain.h create mode 100644 src/tbtr_template_gui_main.cpp create mode 100644 src/tbtr_template_gui_main.h create mode 100644 src/tbtr_template_gui_replaceall.cpp create mode 100644 src/tbtr_template_gui_replaceall.h create mode 100644 src/tbtr_template_vehicle.cpp create mode 100644 src/tbtr_template_vehicle.h create mode 100644 src/tbtr_template_vehicle_func.cpp create mode 100644 src/tbtr_template_vehicle_func.h diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj index 37f9948032..fb821113ca 100644 --- a/projects/openttd_vs100.vcxproj +++ b/projects/openttd_vs100.vcxproj @@ -291,6 +291,18 @@ + + + + + + + + + + + + @@ -869,6 +881,8 @@ + + diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters index 06800ffdaf..f69240b51e 100644 --- a/projects/openttd_vs100.vcxproj.filters +++ b/projects/openttd_vs100.vcxproj.filters @@ -102,6 +102,42 @@ + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + Source Files @@ -1836,6 +1872,12 @@ Save/Load handlers + + Save/Load handlers + + + Save/Load handlers + Tables diff --git a/projects/openttd_vs140.vcxproj b/projects/openttd_vs140.vcxproj index 88f7b44ddd..4dcfd5f04c 100644 --- a/projects/openttd_vs140.vcxproj +++ b/projects/openttd_vs140.vcxproj @@ -308,6 +308,18 @@ + + + + + + + + + + + + @@ -886,6 +898,8 @@ + + diff --git a/projects/openttd_vs140.vcxproj.filters b/projects/openttd_vs140.vcxproj.filters index 06800ffdaf..f69240b51e 100644 --- a/projects/openttd_vs140.vcxproj.filters +++ b/projects/openttd_vs140.vcxproj.filters @@ -102,6 +102,42 @@ + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + Source Files @@ -1836,6 +1872,12 @@ Save/Load handlers + + Save/Load handlers + + + Save/Load handlers + Tables diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj index f859fcf18a..1cb0a38673 100644 --- a/projects/openttd_vs80.vcproj +++ b/projects/openttd_vs80.vcproj @@ -434,6 +434,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -2770,6 +2818,14 @@ RelativePath=".\..\src\saveload\waypoint_sl.cpp" > + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2767,6 +2815,14 @@ RelativePath=".\..\src\saveload\waypoint_sl.cpp" > + + + + subtype, GVSF_VIRTUAL) ) return; + assert(delta == 1 || delta == -1); GroupStatistics &stats_all = GroupStatistics::GetAllGroup(v); @@ -341,6 +345,9 @@ CommandCost CmdDeleteGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 VehicleType vt = g->vehicle_type; + /* Delete all template replacements using the just deleted group */ + deleteIllegalTemplateReplacements(g->index); + /* Delete the Replace Vehicle Windows */ DeleteWindowById(WC_REPLACE_VEHICLE, g->vehicle_type); delete g; diff --git a/src/group_gui.cpp b/src/group_gui.cpp index 81fb1202e4..08a458f642 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -34,6 +34,8 @@ static const int LEVEL_WIDTH = 10; ///< Indenting width of a sub-group in pixels +#include "tbtr_template_gui_main.h" + typedef GUIList GUIGroupList; static const NWidgetPart _nested_group_widgets[] = { @@ -643,6 +645,7 @@ public: case WID_GL_DELETE_GROUP: { // Delete the selected group this->group_confirm = this->vli.index; ShowQuery(STR_QUERY_GROUP_DELETE_CAPTION, STR_GROUP_DELETE_QUERY_TEXT, this, DeleteGroupCallback); + InvalidateWindowData(WC_TEMPLATEGUI_MAIN, 0, 0, 0); break; } @@ -762,6 +765,7 @@ public: virtual void OnQueryTextFinished(char *str) { if (str != NULL) DoCommandP(0, this->group_rename, 0, CMD_ALTER_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_RENAME), NULL, str); + InvalidateWindowData(WC_TEMPLATEGUI_MAIN, 0, 0, 0); this->group_rename = INVALID_GROUP; } @@ -782,6 +786,10 @@ public: assert(this->vehicles.Length() != 0); switch (index) { + case ADI_TEMPLATE_REPLACE: // TemplateReplace Window + if ( vli.vtype == VEH_TRAIN ) + ShowTemplateReplaceWindow(this->unitnumber_digits, this->resize.step_height); + break; case ADI_REPLACE: // Replace window ShowReplaceGroupVehicleWindow(this->vli.index, this->vli.vtype); break; diff --git a/src/lang/english.txt b/src/lang/english.txt index 0bd430bad0..c21cde0b3d 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -4968,3 +4968,62 @@ STR_PLANE :{BLACK}{PLANE} STR_SHIP :{BLACK}{SHIP} STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY}) + +STR_TMPL_RPL_TITLE :{WHITE}Template Replacement +STR_TMPL_TEMPLATE_REPLACEMENT :Template Replacement +STR_TMPL_TRAINS_IN_GROUP :{BLACK}Trains in group +STR_TMPL_AVAILABLE_TEMPLATES :{BLACK}Available Templates +STR_TMPL_DEFINE_TEMPLATE :{BLACK}New +STR_TMPL_EDIT_TEMPLATE :{BLACK}Edit +STR_TMPL_CREATE_CLONE_VEH :{BLACK}Clone +STR_TMPL_DELETE_TEMPLATE :{BLACK}Delete +STR_TMPL_RPL_ALL_TMPL :{BLACK}Replace All Templates +STR_TMPL_NEW_VEHICLE :{BLACK}New Vehicle +STR_TMPL_CONFIRM :{BLACK}Ok +STR_TMPL_CANCEL :{BLACK}Cancel +STR_TMPL_NEW :{BLACK}New Template Vehicle +STR_TMPL_REFIT :{BLACK}Refit +STR_TMPL_GROUP_INFO :{BLACK}Group Info: {ORANGE} +STR_TMPL_TEMPLATE_INFO :{BLACK}Template Info: {ORANGE} +STR_TMPL_RPL_START :{BLACK}Start replacing +STR_TMPL_RPL_STOP :{BLACK}Stop replacing +STR_TMPL_TRAIN_OVR_VALUE :{TINY_FONT}{BLACK}Train Value: {CURRENCY_SHORT} +STR_TMPL_TEMPLATE_OVR_VALUE :{TINY_FONT}{BLACK}Buying Cost: {GOLD}{CURRENCY_LONG} +STR_TMPL_TEMPLATE_OVR_VALUE_nogold :{TINY_FONT}{BLACK}Buying Cost: {CURRENCY_LONG} +STR_TMPL_TEMPLATE_OVR_VALUE_nogoldandcurrency :{TINY_FONT}{BLACK}Buying Cost: +STR_TMPL_TEMPLATE_OVR_VALUE_notinyfont :{BLACK}Buying Cost: {GOLD}{CURRENCY_LONG} +STR_TMPL_TEMPLATE_OVR_VALUE_notinyfontandblack :Buying Cost: {GOLD}{CURRENCY_LONG} +STR_TMPL_WARNING_FREE_WAGON :{RED}Free Chain: not runnable! +STR_TMPL_TEST :{ORANGE}Test String: {RAW_STRING} {RAW_STRING} +STR_TMPL_GROUP_USES_TEMPLATE :{BLACK}Template in use: {NUM} +STR_TMP_TEMPLATE_IN_USE :Template is in use +STR_TMPL_GROUP_NUM_TRAINS :{BLACK}{NUM} +STR_TMPL_CREATEGUI_TITLE :{WHITE}Create/Edit Template Vehicle +STR_TMPL_MAINGUI_DEFINEDGROUPS :{BLACK}Defined Groups for Company +STR_TMPL_TMPLRPL_EX_DIFF_RAILTYPE :Uses Template of different rail type + +STR_TMPL_SET_USEDEPOT :{BLACK}Use vehicles in depot +STR_TMPL_SET_USEDEPOT_TIP :{BLACK}Use vehicles inside the depot that are in a neutral and idle state to compose trains on template replacement in order to reduce buying costs +STR_TMPL_SET_KEEPREMAINDERS :{BLACK}Keep remainders +STR_TMPL_SET_KEEPREMAINDERS_TIP :{BLACK}After finishing template replacement keep all remaining vehicles from the old train in a neutral and idle state for later use +STR_TMPL_SET_REFIT :{BLACK}Use Refit +STR_TMPL_SET_REFIT_TIP :{BLACK}If set, the train will use exactly the cargo refit specified by the template. If not every wagon that is to be newly bought or retrieved from the depot, will *attempt* to be refitted as the old one was. Standard refit if this is impossible. + +STR_TMPL_CONFIG_USEDEPOT :use depot +STR_TMPL_CONFIG_KEEPREMAINDERS :keep rem +STR_TMPL_CONFIG_REFIT :refit + +STR_TMPL_NUM_TRAINS_NEED_RPL :# trains to replace: + +STR_TMPL_CARGO_SUMMARY :{CARGO_LONG} +STR_TMPL_CARGO_SUMMARY_MULTI :{CARGO_LONG} (x{NUM}) + +STR_TMPL_RPLALLGUI_TITLE :{WHITE}Replace all Templace Vehicles +STR_TMPL_RPLALLGUI_INSET_TOP :{BLACK}Choose Vehicle Type and Replacement +STR_TMPL_RPLALLGUI_INSET_TOP_1 :{BLACK}Template Engines +STR_TMPL_RPLALLGUI_INSET_TOP_2 :{BLACK}Buyable Engines +STR_TMPL_RPLALLGUI_INSET_BOTTOM :{BLACK}Current Template List (updated only after replacement) +STR_TMPL_RPLALLGUI_BUTTON_RPLALL :{BLACK}Replace All +STR_TMPL_RPLALLGUI_BUTTON_APPLY :{BLACK}Apply +STR_TMPL_RPLALLGUI_BUTTON_CANCEL :{BLACK}Cancel +STR_TMPL_RPLALLGUI_USE_TIP :{BLACK}Select a vehicle type from each list and press 'Replace All'. If you are happy with the result displayed in the template list, press 'Apply' to actually apply these changes. diff --git a/src/newgrf.h b/src/newgrf.h index 752873a60e..8a894b872c 100644 --- a/src/newgrf.h +++ b/src/newgrf.h @@ -196,4 +196,6 @@ bool GetGlobalVariable(byte param, uint32 *value, const GRFFile *grffile); StringID MapGRFStringID(uint32 grfid, StringID str); void ShowNewGRFError(); +struct TemplateVehicle; + #endif /* NEWGRF_H */ diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 57b29f3f53..650d1aef01 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -1771,7 +1771,8 @@ void CheckOrders(const Vehicle *v) if (v->FirstShared() != v) return; /* Only check every 20 days, so that we don't flood the message log */ - if (v->owner == _local_company && v->day_counter % 20 == 0) { + /* The check is skipped entirely in case the current vehicle is virtual (a.k.a a 'template train') */ + if (v->owner == _local_company && v->day_counter % 20 == 0 && !HasBit(v->subtype, GVSF_VIRTUAL) ) { const Order *order; StringID message = INVALID_STRING_ID; diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 9690481154..9b3b7c27e9 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -775,6 +775,9 @@ bool AfterLoadGame() /* Update all vehicles */ AfterLoadVehicles(true); + /* Update template vehicles */ + AfterLoadTemplateVehicles(); + /* Make sure there is an AI attached to an AI company */ { Company *c; diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index bd3c83d139..32031f4689 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -44,6 +44,8 @@ #include "../fios.h" #include "../error.h" +#include "../tbtr_template_vehicle.h" + #include "table/strings.h" #include "saveload_internal.h" @@ -447,6 +449,8 @@ extern const ChunkHandler _linkgraph_chunk_handlers[]; extern const ChunkHandler _airport_chunk_handlers[]; extern const ChunkHandler _object_chunk_handlers[]; extern const ChunkHandler _persistent_storage_chunk_handlers[]; +extern const ChunkHandler _template_replacement_chunk_handlers[]; +extern const ChunkHandler _template_vehicle_chunk_handlers[]; /** Array of all chunks in a savegame, \c NULL terminated. */ static const ChunkHandler * const _chunk_handlers[] = { @@ -483,6 +487,8 @@ static const ChunkHandler * const _chunk_handlers[] = { _airport_chunk_handlers, _object_chunk_handlers, _persistent_storage_chunk_handlers, + _template_replacement_chunk_handlers, + _template_vehicle_chunk_handlers, NULL, }; @@ -1243,6 +1249,7 @@ static size_t ReferenceToInt(const void *obj, SLRefType rt) switch (rt) { case REF_VEHICLE_OLD: // Old vehicles we save as new ones case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1; + case REF_TEMPLATE_VEHICLE: return ((const TemplateVehicle*)obj)->index + 1; case REF_STATION: return ((const Station*)obj)->index + 1; case REF_TOWN: return ((const Town*)obj)->index + 1; case REF_ORDER: return ((const Order*)obj)->index + 1; @@ -1302,6 +1309,10 @@ static void *IntToReference(size_t index, SLRefType rt) if (Vehicle::IsValidID(index)) return Vehicle::Get(index); SlErrorCorrupt("Referencing invalid Vehicle"); + case REF_TEMPLATE_VEHICLE: + if (TemplateVehicle::IsValidID(index)) return TemplateVehicle::Get(index); + SlErrorCorrupt("Referencing invalid TemplateVehicle"); + case REF_STATION: if (Station::IsValidID(index)) return Station::Get(index); SlErrorCorrupt("Referencing invalid Station"); diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index 72c51fa69d..8ca32ac3a7 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -85,6 +85,7 @@ enum SLRefType { REF_STORAGE = 9, ///< Load/save a reference to a persistent storage. REF_LINK_GRAPH = 10, ///< Load/save a reference to a link graph. REF_LINK_GRAPH_JOB = 11, ///< Load/save a reference to a link graph job. + REF_TEMPLATE_VEHICLE = 12, ///< Load/save a reference to a template vehicle }; /** Highest possible savegame version. */ diff --git a/src/saveload/saveload_internal.h b/src/saveload/saveload_internal.h index 74e5b9936d..67b3038a04 100644 --- a/src/saveload/saveload_internal.h +++ b/src/saveload/saveload_internal.h @@ -28,6 +28,7 @@ const SaveLoad *GetBaseStationDescription(); void AfterLoadVehicles(bool part_of_load); void FixupTrainLengths(); +void AfterLoadTemplateVehicles(); void AfterLoadStations(); void AfterLoadRoadStops(); void AfterLoadLabelMaps(); diff --git a/src/saveload/tbtr_template_replacement_sl.cpp b/src/saveload/tbtr_template_replacement_sl.cpp new file mode 100644 index 0000000000..d9b1448ebe --- /dev/null +++ b/src/saveload/tbtr_template_replacement_sl.cpp @@ -0,0 +1,35 @@ +#include "../stdafx.h" + +#include "../tbtr_template_vehicle.h" + +#include "saveload.h" + +static const SaveLoad _template_replacement_desc[] = { + SLE_VAR(TemplateReplacement, sel_template, SLE_UINT16), + SLE_VAR(TemplateReplacement, group, SLE_UINT16), + SLE_END() +}; + +static void Save_TMPL_RPLS() +{ + TemplateReplacement *tr; + + FOR_ALL_TEMPLATE_REPLACEMENTS(tr) { + SlSetArrayIndex(tr->index); + SlObject(tr, _template_replacement_desc); + } +} + +static void Load_TMPL_RPLS() +{ + int index; + + while ((index = SlIterateArray()) != -1) { + TemplateReplacement *tr = new (index) TemplateReplacement(); + SlObject(tr, _template_replacement_desc); + } +} + +extern const ChunkHandler _template_replacement_chunk_handlers[] = { + {'TRPL', Save_TMPL_RPLS, Load_TMPL_RPLS, NULL, NULL, CH_ARRAY | CH_LAST}, +}; diff --git a/src/saveload/tbtr_template_veh_sl.cpp b/src/saveload/tbtr_template_veh_sl.cpp new file mode 100644 index 0000000000..3c6ca9e0b6 --- /dev/null +++ b/src/saveload/tbtr_template_veh_sl.cpp @@ -0,0 +1,99 @@ +#include "../stdafx.h" + +#include "../tbtr_template_vehicle.h" + +#include "saveload.h" + +const SaveLoad* GTD() { + + static const SaveLoad _template_veh_desc[] = { + SLE_REF(TemplateVehicle, next, REF_TEMPLATE_VEHICLE), + + SLE_VAR(TemplateVehicle, reuse_depot_vehicles, SLE_UINT8), + SLE_VAR(TemplateVehicle, keep_remaining_vehicles, SLE_UINT8), + SLE_VAR(TemplateVehicle, refit_as_template, SLE_UINT8), + + SLE_VAR(TemplateVehicle, owner, SLE_UINT32), + SLE_VAR(TemplateVehicle, owner_b, SLE_UINT8), + + SLE_VAR(TemplateVehicle, engine_type, SLE_UINT16), + SLE_VAR(TemplateVehicle, cargo_type, SLE_UINT8), + SLE_VAR(TemplateVehicle, cargo_cap, SLE_UINT16), + SLE_VAR(TemplateVehicle, cargo_subtype, SLE_UINT8), + + SLE_VAR(TemplateVehicle, subtype, SLE_UINT8), + SLE_VAR(TemplateVehicle, railtype, SLE_UINT8), + + SLE_VAR(TemplateVehicle, index, SLE_UINT32), + + SLE_VAR(TemplateVehicle, real_consist_length, SLE_UINT16), + + SLE_VAR(TemplateVehicle, max_speed, SLE_UINT16), + SLE_VAR(TemplateVehicle, power, SLE_UINT32), + SLE_VAR(TemplateVehicle, weight, SLE_UINT32), + SLE_VAR(TemplateVehicle, max_te, SLE_UINT32), + + SLE_VAR(TemplateVehicle, spritenum, SLE_UINT8), + SLE_VAR(TemplateVehicle, cur_image, SLE_UINT32), + SLE_VAR(TemplateVehicle, image_width, SLE_UINT32), + + SLE_END() + }; + + static const SaveLoad * const _ret[] = { + _template_veh_desc, + }; + + return _ret[0]; +} + +static void Save_TMPLS() +{ + TemplateVehicle *tv; + + FOR_ALL_TEMPLATES(tv) { + SlSetArrayIndex(tv->index); + SlObject(tv, GTD()); + } +} + +static void Load_TMPLS() +{ + int index; + + while ((index = SlIterateArray()) != -1) { + TemplateVehicle *tv = new (index) TemplateVehicle(); //TODO:check with veh sl code + SlObject(tv, GTD()); + } +} + +static void Ptrs_TMPLS() +{ + TemplateVehicle *tv; + FOR_ALL_TEMPLATES(tv) { + SlObject(tv, GTD()); + } +} + +void AfterLoadTemplateVehicles() +{ + TemplateVehicle *tv; + + FOR_ALL_TEMPLATES(tv) { + /* Reinstate the previous pointer */ + if (tv->next != NULL) tv->next->previous = tv; + tv->first =NULL; + } + FOR_ALL_TEMPLATES(tv) { + /* Fill the first pointers */ + if (tv->previous == NULL) { + for (TemplateVehicle *u = tv; u != NULL; u = u->Next()) { + u->first = tv; + } + } + } +} + +extern const ChunkHandler _template_vehicle_chunk_handlers[] = { + {'TMPL', Save_TMPLS, Load_TMPLS, Ptrs_TMPLS, NULL, CH_ARRAY | CH_LAST}, +}; diff --git a/src/tbtr_template_gui_create.cpp b/src/tbtr_template_gui_create.cpp new file mode 100644 index 0000000000..c2dc436cab --- /dev/null +++ b/src/tbtr_template_gui_create.cpp @@ -0,0 +1,459 @@ +#include "stdafx.h" + +#include "gfx_func.h" +#include "direction_type.h" + +#include "strings_func.h" +#include "window_func.h" +#include "company_func.h" +#include "window_gui.h" +#include "settings_func.h" +#include "core/geometry_func.hpp" +#include "table/sprites.h" +#include "table/strings.h" +#include "viewport_func.h" +#include "window_func.h" +#include "gui.h" +#include "textbuf_gui.h" +#include "command_func.h" +#include "depot_base.h" +#include "vehicle_gui.h" +#include "spritecache.h" +#include "strings_func.h" +#include "window_func.h" +#include "vehicle_func.h" +#include "company_func.h" +#include "tilehighlight_func.h" +#include "window_gui.h" +#include "vehiclelist.h" +#include "order_backup.h" +#include "group.h" +#include "company_base.h" + +#include "tbtr_template_gui_create.h" +#include "tbtr_template_vehicle.h" +#include "tbtr_template_vehicle_func.h" + +#include "train.h" + +class TemplateReplaceWindow; + +// some space in front of the virtual train in the matrix +uint16 TRAIN_FRONT_SPACE = 16; + +enum TemplateReplaceWindowWidgets { + TCW_CAPTION, + TCW_MATRIX_NEW_TMPL, + TCW_INFO_PANEL, + TCW_SCROLLBAR_NEW_TMPL, + TCW_SELL_TMPL, + TCW_NEW, + TCW_OK, + TCW_CANCEL, + TCW_REFIT, + TCW_CLONE, +}; + +static const NWidgetPart _widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, TCW_CAPTION), SetDataTip(STR_TMPL_CREATEGUI_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_VERTICAL), + NWidget(WWT_MATRIX, COLOUR_GREY, TCW_MATRIX_NEW_TMPL), SetMinimalSize(216, 60), SetFill(1, 0), SetDataTip(0x1, STR_REPLACE_HELP_LEFT_ARRAY), SetResize(1, 0), SetScrollbar(TCW_SCROLLBAR_NEW_TMPL), + NWidget(WWT_PANEL, COLOUR_GREY, TCW_INFO_PANEL), SetMinimalSize(216,80), SetResize(1,1), EndContainer(), + NWidget(NWID_HSCROLLBAR, COLOUR_GREY, TCW_SCROLLBAR_NEW_TMPL), SetResize(1,0), + EndContainer(), + NWidget(WWT_IMGBTN, COLOUR_GREY, TCW_SELL_TMPL), SetDataTip(0x0, STR_NULL), SetMinimalSize(23,23), SetResize(0, 1), SetFill(0, 1), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TCW_OK), SetMinimalSize(52, 12), SetResize(1,0), SetDataTip(STR_TMPL_CONFIRM, STR_TMPL_CONFIRM), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TCW_NEW), SetMinimalSize(52, 12), SetResize(1,0), SetDataTip(STR_TMPL_NEW, STR_TMPL_NEW), + NWidget(WWT_TEXTBTN, COLOUR_GREY, TCW_CLONE), SetMinimalSize(52, 12), SetResize(1,0), SetDataTip(STR_TMPL_CREATE_CLONE_VEH, STR_TMPL_CREATE_CLONE_VEH), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TCW_REFIT), SetMinimalSize(52, 12), SetResize(1,0), SetDataTip(STR_TMPL_REFIT, STR_TMPL_REFIT), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TCW_CANCEL), SetMinimalSize(52, 12), SetResize(1,0), SetDataTip(STR_TMPL_CANCEL, STR_TMPL_CANCEL), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + +static WindowDesc _template_create_window_desc( + WDP_AUTO, // window position + "template create window", // const char* ini_key + 456, 100, // window size + WC_CREATE_TEMPLATE, // window class + WC_TEMPLATEGUI_MAIN, // parent window class + WDF_CONSTRUCTION, // window flags + _widgets, lengthof(_widgets) // widgets + num widgets +); + +static void TrainDepotMoveVehicle(const Vehicle *wagon, VehicleID sel, const Vehicle *head) +{ + const Vehicle *v = Vehicle::Get(sel); + + if (v == wagon) return; + + if (wagon == NULL) { + if (head != NULL) wagon = head->Last(); + } else { + wagon = wagon->Previous(); + if (wagon == NULL) return; + } + + if (wagon == v) return; + + CmdMoveRailVehicle(INVALID_TILE, DC_EXEC, (_ctrl_pressed ? 1:0)<<20 | (1<<21) | v->index, wagon == NULL ? INVALID_VEHICLE : wagon->index, 0); +} + +class TemplateCreateWindow : public Window { +private: + Scrollbar *hscroll; + int line_height; + Train* virtual_train; + bool editMode; + bool *noticeParent; + bool *createWindowOpen; /// used to notify main window of progress (dummy way of disabling 'delete' while editing a template) + bool virtualTrainChangedNotice; + VehicleID sel; + VehicleID vehicle_over; + TemplateVehicle *editTemplate; + +public: + TemplateCreateWindow(WindowDesc* _wdesc, TemplateVehicle *to_edit, bool *notice, bool *windowOpen, int step_h) : Window(_wdesc) + { + this->line_height = step_h; + this->CreateNestedTree(_wdesc); + this->hscroll = this->GetScrollbar(TCW_SCROLLBAR_NEW_TMPL); + this->FinishInitNested(VEH_TRAIN); + /* a sprite */ + this->GetWidget(TCW_SELL_TMPL)->widget_data = SPR_SELL_TRAIN; + + this->owner = _local_company; + + noticeParent = notice; + createWindowOpen = windowOpen; + virtualTrainChangedNotice = false; + this->editTemplate = to_edit; + + if ( to_edit ) editMode = true; + else editMode = false; + + this->sel = INVALID_VEHICLE; + this->vehicle_over = INVALID_VEHICLE; + + this->virtual_train = VirtualTrainFromTemplateVehicle(to_edit); + + this->resize.step_height = 1; + } + ~TemplateCreateWindow() + { + if ( virtual_train ) + delete virtual_train; + + SetWindowClassesDirty(WC_TRAINS_LIST); + + /* more cleanup */ + *createWindowOpen = false; + DeleteWindowById(WC_BUILD_VIRTUAL_TRAIN, this->window_number); + + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case TCW_MATRIX_NEW_TMPL: + size->height = 20; + break; + } + } + virtual void OnResize() + { + NWidgetCore *nwi = this->GetWidget(TCW_MATRIX_NEW_TMPL); + this->hscroll->SetCapacity(nwi->current_x); + nwi->widget_data = (this->hscroll->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START); + } + + + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + virtualTrainChangedNotice = true; + } + virtual void OnClick(Point pt, int widget, int click_count) + { + switch(widget) { + case TCW_MATRIX_NEW_TMPL: { + NWidgetBase *nwi = this->GetWidget(TCW_MATRIX_NEW_TMPL); + ClickedOnVehiclePanel(pt.x - nwi->pos_x-TRAIN_FRONT_SPACE, pt.y - nwi->pos_y); + break; + } + case TCW_NEW: { + ShowBuildVirtualTrainWindow(&virtual_train, &virtualTrainChangedNotice); + break; + } + case TCW_CLONE: { + this->SetWidgetDirty(TCW_CLONE); + this->ToggleWidgetLoweredState(TCW_CLONE); + if (this->IsWidgetLowered(TCW_CLONE)) { + static const CursorID clone_icon = SPR_CURSOR_CLONE_TRAIN; + SetObjectToPlaceWnd(clone_icon, PAL_NONE, HT_VEHICLE, this); + } else { + ResetObjectToPlace(); + } + break; + } + case TCW_OK: { + TemplateVehicle *tv = NULL; + if ( editMode ) tv = DeleteTemplateVehicle(editTemplate); + editTemplate = TemplateVehicleFromVirtualTrain(virtual_train); + if ( tv ) *noticeParent = true; + delete this; + break; + } + case TCW_CANCEL: { + delete this; + break; + } + case TCW_REFIT: { + ShowVehicleRefitWindow(virtual_train, INVALID_VEH_ORDER_ID, this, false, true); + break; + } + } + } + virtual bool OnVehicleSelect(const Vehicle *v) + { + // throw away the current virtual train + if ( virtual_train ) + delete this->virtual_train; + // create a new one + this->virtual_train = CloneVirtualTrainFromTrain((const Train*)v); + this->ToggleWidgetLoweredState(TCW_CLONE); + ResetObjectToPlace(); + this->SetDirty(); + + return true; + } + virtual void DrawWidget(const Rect &r, int widget) const + { + switch(widget) { + case TCW_MATRIX_NEW_TMPL: { + if ( this->virtual_train ) { + DrawTrainImage(virtual_train, r.left+TRAIN_FRONT_SPACE, r.right, r.top+2, this->sel, EIT_PURCHASE, this->hscroll->GetPosition(), this->vehicle_over); + SetDParam(0, CeilDiv(virtual_train->gcache.cached_total_length * 10, TILE_SIZE)); + SetDParam(1, 1); + DrawString(r.left, r.right, r.top, STR_TINY_BLACK_DECIMAL, TC_BLACK, SA_RIGHT); + } + break; + } + case TCW_INFO_PANEL: { + if ( this->virtual_train ) { + /* Draw vehicle performance info */ + const GroundVehicleCache *gcache = this->virtual_train->GetGroundVehicleCache(); + SetDParam(2, this->virtual_train->GetDisplayMaxSpeed()); + SetDParam(1, gcache->cached_power); + SetDParam(0, gcache->cached_weight); + SetDParam(3, gcache->cached_max_te / 1000); + DrawString(r.left+8, r.right, r.top+4, STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE); + /* Draw cargo summary */ + CargoArray cargo_caps; + for ( const Train *tmp=this->virtual_train; tmp; tmp=tmp->Next() ) + cargo_caps[tmp->cargo_type] += tmp->cargo_cap; + int y = r.top+24; + for (CargoID i = 0; i < NUM_CARGO; ++i) { + if ( cargo_caps[i] > 0 ) { + SetDParam(0, i); + SetDParam(1, cargo_caps[i]); + SetDParam(2, _settings_game.vehicle.freight_trains); + DrawString(r.left+8, r.right, y, STR_TMPL_CARGO_SUMMARY, TC_WHITE, SA_LEFT); + y += this->line_height/2; + } + } + } + break; + } + default: + break; + } + } + virtual void OnTick() + { + if ( virtualTrainChangedNotice ) { + this->SetDirty(); + virtualTrainChangedNotice = false; + } + } + virtual void OnDragDrop(Point pt, int widget) + { + switch (widget) { + case TCW_MATRIX_NEW_TMPL: { + const Vehicle *v = NULL; + VehicleID sel; + if ( virtual_train ) sel = virtual_train->index; + else sel = INVALID_VEHICLE; + + this->SetDirty(); + + NWidgetBase *nwi = this->GetWidget(TCW_MATRIX_NEW_TMPL); + GetDepotVehiclePtData gdvp = { NULL, NULL }; + + if (this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, &gdvp) == MODE_DRAG_VEHICLE && sel != INVALID_VEHICLE) { + if (gdvp.wagon == NULL || gdvp.wagon->index != sel) { + this->vehicle_over = INVALID_VEHICLE; + TrainDepotMoveVehicle(gdvp.wagon, sel, gdvp.head); + virtual_train = virtual_train->First(); + } + } + break; + } + case TCW_SELL_TMPL: { + if (this->IsWidgetDisabled(widget)) return; + if (this->sel == INVALID_VEHICLE) return; + + virtual_train = DeleteVirtualTrain(virtual_train, Train::Get(this->sel)); + + this->sel = INVALID_VEHICLE; + + this->SetDirty(); + break; + } + default: + this->sel = INVALID_VEHICLE; + this->SetDirty(); + } + _cursor.vehchain = false; + this->sel = INVALID_VEHICLE; + this->SetDirty(); + } + virtual void OnMouseDrag(Point pt, int widget) + { + if (this->sel == INVALID_VEHICLE) return; + /* A rail vehicle is dragged.. */ + if (widget != TCW_MATRIX_NEW_TMPL) { // ..outside of the depot matrix. + if (this->vehicle_over != INVALID_VEHICLE) { + this->vehicle_over = INVALID_VEHICLE; + this->SetWidgetDirty(TCW_MATRIX_NEW_TMPL); + } + return; + } + + NWidgetBase *matrix = this->GetWidget(widget); + const Vehicle *v = NULL; + GetDepotVehiclePtData gdvp = {NULL, NULL}; + + if (this->GetVehicleFromDepotWndPt(pt.x - matrix->pos_x, pt.y - matrix->pos_y, &v, &gdvp) != MODE_DRAG_VEHICLE) return; + VehicleID new_vehicle_over = INVALID_VEHICLE; + if (gdvp.head != NULL) { + if (gdvp.wagon == NULL && gdvp.head->Last()->index != this->sel) { // ..at the end of the train. + /* NOTE: As a wagon can't be moved at the begin of a train, head index isn't used to mark a drag-and-drop + * destination inside a train. This head index is then used to indicate that a wagon is inserted at + * the end of the train. + */ + new_vehicle_over = gdvp.head->index; + } else if (gdvp.wagon != NULL && gdvp.head != gdvp.wagon && + gdvp.wagon->index != this->sel && + gdvp.wagon->Previous()->index != this->sel) { // ..over an existing wagon. + new_vehicle_over = gdvp.wagon->index; + } + } + if (this->vehicle_over == new_vehicle_over) return; + + this->vehicle_over = new_vehicle_over; + this->SetWidgetDirty(widget); + } + virtual void OnPaint() + { + uint max_width = 32; + uint width = 0; + if ( virtual_train ) + for (Train *v = virtual_train; v != NULL; v = v->Next()) + width += v->GetDisplayImageWidth(); + + max_width = max(max_width, width); + this->hscroll->SetCount(max_width+25); + + this->DrawWidgets(); + } + struct GetDepotVehiclePtData { + const Vehicle *head; + const Vehicle *wagon; + }; + + enum DepotGUIAction { + MODE_ERROR, + MODE_DRAG_VEHICLE, + MODE_SHOW_VEHICLE, + MODE_START_STOP, + }; + + uint count_width; + uint header_width; + DepotGUIAction GetVehicleFromDepotWndPt(int x, int y, const Vehicle **veh, GetDepotVehiclePtData *d) const + { + const NWidgetCore *matrix_widget = this->GetWidget(TCW_MATRIX_NEW_TMPL); + /* In case of RTL the widgets are swapped as a whole */ + if (_current_text_dir == TD_RTL) x = matrix_widget->current_x - x; + + uint xm = x; + + bool wagon = false; + + x += this->hscroll->GetPosition(); + const Train *v = virtual_train; + d->head = d->wagon = v; + + if (xm <= this->header_width) { + + if (wagon) return MODE_ERROR; + + return MODE_SHOW_VEHICLE; + } + + /* Account for the header */ + x -= this->header_width; + + /* find the vehicle in this row that was clicked */ + for (; v != NULL; v = v->Next()) { + x -= v->GetDisplayImageWidth(); + if (x < 0) break; + } + + d->wagon = (v != NULL ? v->GetFirstEnginePart() : NULL); + + return MODE_DRAG_VEHICLE; + } + + void ClickedOnVehiclePanel(int x, int y) + { + GetDepotVehiclePtData gdvp = { NULL, NULL }; + const Vehicle *v = NULL; + this->GetVehicleFromDepotWndPt(x, y, &v, &gdvp); + + v = gdvp.wagon; + + if (v != NULL && VehicleClicked(v)) return; + VehicleID sel = this->sel; + + if (sel != INVALID_VEHICLE) { + this->sel = INVALID_VEHICLE; + } else if (v != NULL) { + int image = v->GetImage(_current_text_dir == TD_RTL ? DIR_E : DIR_W, EIT_PURCHASE); + SetObjectToPlaceWnd(image, GetVehiclePalette(v), HT_DRAG, this); + + this->sel = v->index; + this->SetDirty(); + + _cursor.short_vehicle_offset = v->IsGroundVehicle() ? 16 - v->GetGroundVehicleCache()->cached_veh_length * 2 : 0; + _cursor.vehchain = _ctrl_pressed; + } + } + +}; + +void ShowTemplateCreateWindow(TemplateVehicle *to_edit, bool *noticeParent, bool *createWindowOpen, int step_h) +{ + if ( BringWindowToFrontById(WC_CREATE_TEMPLATE, VEH_TRAIN) != NULL ) return; + new TemplateCreateWindow(&_template_create_window_desc, to_edit, noticeParent, createWindowOpen, step_h); +} + + diff --git a/src/tbtr_template_gui_create.h b/src/tbtr_template_gui_create.h new file mode 100644 index 0000000000..4ab054a60c --- /dev/null +++ b/src/tbtr_template_gui_create.h @@ -0,0 +1,11 @@ +// template creation gui + +#ifndef TEMPLATE_GUI_CREATE +#define TEMPLATE_GUI_CREATE + +#include "tbtr_template_vehicle.h" +#include "tbtr_template_gui_create_virtualtrain.h" + +void ShowTemplateCreateWindow(TemplateVehicle*, bool*, bool*, int); + +#endif diff --git a/src/tbtr_template_gui_create_virtualtrain.cpp b/src/tbtr_template_gui_create_virtualtrain.cpp new file mode 100644 index 0000000000..23351671dd --- /dev/null +++ b/src/tbtr_template_gui_create_virtualtrain.cpp @@ -0,0 +1,829 @@ +/* $Id: build_vehicle_gui.cpp 23792 2012-01-12 19:23:00Z yexo $ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file build_vehicle_gui.cpp GUI for building vehicles. */ + +#include "stdafx.h" +#include "engine_base.h" +#include "engine_func.h" +#include "station_base.h" +#include "articulated_vehicles.h" +#include "textbuf_gui.h" +#include "command_func.h" +#include "company_func.h" +#include "vehicle_gui.h" +#include "newgrf_engine.h" +#include "newgrf_text.h" +#include "group.h" +#include "string_func.h" +#include "strings_func.h" +#include "window_func.h" +#include "date_func.h" +#include "vehicle_func.h" +#include "widgets/dropdown_func.h" +#include "engine_gui.h" +#include "cargotype.h" +#include "core/geometry_func.hpp" + +#include "widgets/build_vehicle_widget.h" + +#include "table/strings.h" + +#include "tbtr_template_gui_create_virtualtrain.h" + +#include "vehicle_gui.h" + +static const NWidgetPart _nested_build_vehicle_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_BV_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_VERTICAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SORT_ASCENDING_DESCENDING), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), + NWidget(NWID_SPACER), SetFill(1, 1), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_SORT_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_CARGO_FILTER_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA), + EndContainer(), + EndContainer(), + EndContainer(), + /* Vehicle list. */ + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_BV_LIST), SetResize(1, 1), SetFill(1, 0), SetDataTip(0x101, STR_NULL), SetScrollbar(WID_BV_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_BV_SCROLLBAR), + EndContainer(), + /* Panel with details. */ + NWidget(WWT_PANEL, COLOUR_GREY, WID_BV_PANEL), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), + /* Build/rename buttons, resize button. */ + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_BUILD), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_TMPL_CONFIRM, STR_TMPL_CONFIRM), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_RENAME), SetResize(1, 0), SetFill(1, 0), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + +/** Special cargo filter criteria */ +static const CargoID CF_ANY = CT_NO_REFIT; ///< Show all vehicles independent of carried cargo (i.e. no filtering) +static const CargoID CF_NONE = CT_INVALID; ///< Show only vehicles which do not carry cargo (e.g. train engines) + +static bool _internal_sort_order; ///< false = descending, true = ascending +static byte _last_sort_criteria[] = {0, 0, 0, 0}; +static bool _last_sort_order[] = {false, false, false, false}; +static CargoID _last_filter_criteria[] = {CF_ANY, CF_ANY, CF_ANY, CF_ANY}; + +/** + * Determines order of engines by engineID + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineNumberSorter(const EngineID *a, const EngineID *b) +{ + int r = Engine::Get(*a)->list_position - Engine::Get(*b)->list_position; + + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by introduction date + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineIntroDateSorter(const EngineID *a, const EngineID *b) +{ + const int va = Engine::Get(*a)->intro_date; + const int vb = Engine::Get(*b)->intro_date; + const int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by name + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineNameSorter(const EngineID *a, const EngineID *b) +{ + static EngineID last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE }; + static char last_name[2][64] = { "\0", "\0" }; + + const EngineID va = *a; + const EngineID vb = *b; + + if (va != last_engine[0]) { + last_engine[0] = va; + SetDParam(0, va); + GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0])); + } + + if (vb != last_engine[1]) { + last_engine[1] = vb; + SetDParam(0, vb); + GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1])); + } + + int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by reliability + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineReliabilitySorter(const EngineID *a, const EngineID *b) +{ + const int va = Engine::Get(*a)->reliability; + const int vb = Engine::Get(*b)->reliability; + const int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by purchase cost + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineCostSorter(const EngineID *a, const EngineID *b) +{ + Money va = Engine::Get(*a)->GetCost(); + Money vb = Engine::Get(*b)->GetCost(); + int r = ClampToI32(va - vb); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by speed + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineSpeedSorter(const EngineID *a, const EngineID *b) +{ + int va = Engine::Get(*a)->GetDisplayMaxSpeed(); + int vb = Engine::Get(*b)->GetDisplayMaxSpeed(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by power + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EnginePowerSorter(const EngineID *a, const EngineID *b) +{ + int va = Engine::Get(*a)->GetPower(); + int vb = Engine::Get(*b)->GetPower(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by tractive effort + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineTractiveEffortSorter(const EngineID *a, const EngineID *b) +{ + int va = Engine::Get(*a)->GetDisplayMaxTractiveEffort(); + int vb = Engine::Get(*b)->GetDisplayMaxTractiveEffort(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by running costs + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineRunningCostSorter(const EngineID *a, const EngineID *b) +{ + Money va = Engine::Get(*a)->GetRunningCost(); + Money vb = Engine::Get(*b)->GetRunningCost(); + int r = ClampToI32(va - vb); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of engines by running costs + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EnginePowerVsRunningCostSorter(const EngineID *a, const EngineID *b) +{ + const Engine *e_a = Engine::Get(*a); + const Engine *e_b = Engine::Get(*b); + + /* Here we are using a few tricks to get the right sort. + * We want power/running cost, but since we usually got higher running cost than power and we store the result in an int, + * we will actually calculate cunning cost/power (to make it more than 1). + * Because of this, the return value have to be reversed as well and we return b - a instead of a - b. + * Another thing is that both power and running costs should be doubled for multiheaded engines. + * Since it would be multipling with 2 in both numerator and denumerator, it will even themselves out and we skip checking for multiheaded. */ + Money va = (e_a->GetRunningCost()) / max(1U, (uint)e_a->GetPower()); + Money vb = (e_b->GetRunningCost()) / max(1U, (uint)e_b->GetPower()); + int r = ClampToI32(vb - va); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/* Train sorting functions */ + +/** + * Determines order of train engines by capacity + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL TrainEngineCapacitySorter(const EngineID *a, const EngineID *b) +{ + const RailVehicleInfo *rvi_a = RailVehInfo(*a); + const RailVehicleInfo *rvi_b = RailVehInfo(*b); + + int va = GetTotalCapacityOfArticulatedParts(*a) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); + int vb = GetTotalCapacityOfArticulatedParts(*b) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** + * Determines order of train engines by engine / wagon + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL TrainEnginesThenWagonsSorter(const EngineID *a, const EngineID *b) +{ + int val_a = (RailVehInfo(*a)->railveh_type == RAILVEH_WAGON ? 1 : 0); + int val_b = (RailVehInfo(*b)->railveh_type == RAILVEH_WAGON ? 1 : 0); + int r = val_a - val_b; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _internal_sort_order ? -r : r; +} + +/** Sort functions for the vehicle sort criteria, for each vehicle type. */ +static EngList_SortTypeFunction * const _sorter[][11] = {{ + /* Trains */ + &EngineNumberSorter, + &EngineCostSorter, + &EngineSpeedSorter, + &EnginePowerSorter, + &EngineTractiveEffortSorter, + &EngineIntroDateSorter, + &EngineNameSorter, + &EngineRunningCostSorter, + &EnginePowerVsRunningCostSorter, + &EngineReliabilitySorter, + &TrainEngineCapacitySorter, +}}; + +static const StringID _sort_listing[][12] = {{ + /* Trains */ + STR_SORT_BY_ENGINE_ID, + STR_SORT_BY_COST, + STR_SORT_BY_MAX_SPEED, + STR_SORT_BY_POWER, + STR_SORT_BY_TRACTIVE_EFFORT, + STR_SORT_BY_INTRO_DATE, + STR_SORT_BY_NAME, + STR_SORT_BY_RUNNING_COST, + STR_SORT_BY_POWER_VS_RUNNING_COST, + STR_SORT_BY_RELIABILITY, + STR_SORT_BY_CARGO_CAPACITY, + INVALID_STRING_ID +}}; + +/** Cargo filter functions */ +static bool CDECL CargoFilter(const EngineID *eid, const CargoID cid) +{ + if (cid == CF_ANY) return true; + uint32 refit_mask = GetUnionOfArticulatedRefitMasks(*eid, true); + return (cid == CF_NONE ? refit_mask == 0 : HasBit(refit_mask, cid)); +} + +static GUIEngineList::FilterFunction * const _filter_funcs[] = { + &CargoFilter, +}; + +/** + * Engine drawing loop + * @param type Type of vehicle (VEH_*) + * @param l The left most location of the list + * @param r The right most location of the list + * @param y The top most location of the list + * @param eng_list What engines to draw + * @param min where to start in the list + * @param max where in the list to end + * @param selected_id what engine to highlight as selected, if any + * @param show_count Whether to show the amount of engines or not + * @param selected_group the group to list the engines of + */ +static void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group) +{ + static const int sprite_widths[] = { 60, 60, 76, 67 }; + static const int sprite_y_offsets[] = { -1, -1, -2, -2 }; + + /* Obligatory sanity checks! */ + assert((uint)type < lengthof(sprite_widths)); + assert_compile(lengthof(sprite_y_offsets) == lengthof(sprite_widths)); + assert(max <= eng_list->Length()); + + bool rtl = _current_text_dir == TD_RTL; + int step_size = GetEngineListHeight(type); + int sprite_width = sprite_widths[type]; + + int sprite_x = (rtl ? r - sprite_width / 2 : l + sprite_width / 2) - 1; + int sprite_y_offset = sprite_y_offsets[type] + step_size / 2; + + int text_left = l + (rtl ? WD_FRAMERECT_LEFT : sprite_width); + int text_right = r - (rtl ? sprite_width : WD_FRAMERECT_RIGHT); + + int normal_text_y_offset = (step_size - FONT_HEIGHT_NORMAL) / 2; + int small_text_y_offset = step_size - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1; + + for (; min < max; min++, y += step_size) { + const EngineID engine = (*eng_list)[min]; + /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */ + const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine); + + SetDParam(0, engine); + DrawString(text_left, text_right, y + normal_text_y_offset, STR_ENGINE_NAME, engine == selected_id ? TC_WHITE : TC_BLACK); + DrawVehicleEngine(l, r, sprite_x, y + sprite_y_offset, engine, (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE); + if (show_count) { + SetDParam(0, num_engines); + DrawString(text_left, text_right, y + small_text_y_offset, STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT); + } + } +} + + +struct BuildVirtualTrainWindow : Window { + VehicleType vehicle_type; + union { + RailTypeByte railtype; + RoadTypes roadtypes; + } filter; + bool descending_sort_order; + byte sort_criteria; + bool listview_mode; + EngineID sel_engine; + EngineID rename_engine; + GUIEngineList eng_list; + CargoID cargo_filter[NUM_CARGO + 2]; ///< Available cargo filters; CargoID or CF_ANY or CF_NONE + StringID cargo_filter_texts[NUM_CARGO + 3]; ///< Texts for filter_cargo, terminated by INVALID_STRING_ID + byte cargo_filter_criteria; ///< Selected cargo filter + int details_height; ///< Minimal needed height of the details panels (found so far). + Scrollbar *vscroll; + Train **virtual_train; ///< the virtual train that is currently being created + bool *noticeParent; + + BuildVirtualTrainWindow(WindowDesc *desc, Train **vt, bool *notice) : Window(desc) + { + this->vehicle_type = VEH_TRAIN; + this->window_number = 0;//tile == INVALID_TILE ? (int)type : tile; + + this->sel_engine = INVALID_ENGINE; + + this->sort_criteria = _last_sort_criteria[VEH_TRAIN]; + this->descending_sort_order = _last_sort_order[VEH_TRAIN]; + + this->filter.railtype = RAILTYPE_END; + + this->listview_mode = (this->window_number <= VEH_END); + + this->CreateNestedTree(desc); + + this->vscroll = this->GetScrollbar(WID_BV_SCROLLBAR); + + NWidgetCore *widget = this->GetWidget(WID_BV_LIST); + + widget = this->GetWidget(WID_BV_BUILD); + + widget = this->GetWidget(WID_BV_RENAME); + widget->widget_data = STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON + VEH_TRAIN; + widget->tool_tip = STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP + VEH_TRAIN; + + this->details_height = ((this->vehicle_type == VEH_TRAIN) ? 10 : 9) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + + this->FinishInitNested(VEH_TRAIN); + + this->owner = _local_company; + + this->eng_list.ForceRebuild(); + this->GenerateBuildList(); + + if (this->eng_list.Length() > 0) this->sel_engine = this->eng_list[0]; + + this->virtual_train = vt; + this->noticeParent = notice; + } + + /** Populate the filter list and set the cargo filter criteria. */ + void SetCargoFilterArray() + { + uint filter_items = 0; + + /* Add item for disabling filtering. */ + this->cargo_filter[filter_items] = CF_ANY; + this->cargo_filter_texts[filter_items] = STR_PURCHASE_INFO_ALL_TYPES; + filter_items++; + + /* Add item for vehicles not carrying anything, e.g. train engines. + * This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */ + if (this->vehicle_type == VEH_TRAIN) { + this->cargo_filter[filter_items] = CF_NONE; + this->cargo_filter_texts[filter_items] = STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE; + filter_items++; + } + + /* Collect available cargo types for filtering. */ + const CargoSpec *cs; + FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { + this->cargo_filter[filter_items] = cs->Index(); + this->cargo_filter_texts[filter_items] = cs->name; + filter_items++; + } + + /* Terminate the filter list. */ + this->cargo_filter_texts[filter_items] = INVALID_STRING_ID; + + /* If not found, the cargo criteria will be set to all cargoes. */ + this->cargo_filter_criteria = 0; + + /* Find the last cargo filter criteria. */ + for (uint i = 0; i < filter_items; ++i) { + if (this->cargo_filter[i] == _last_filter_criteria[this->vehicle_type]) { + this->cargo_filter_criteria = i; + break; + } + } + + this->eng_list.SetFilterFuncs(_filter_funcs); + this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY); + } + + void OnInit() + { + this->SetCargoFilterArray(); + } + + /** Filter the engine list against the currently selected cargo filter */ + void FilterEngineList() + { + this->eng_list.Filter(this->cargo_filter[this->cargo_filter_criteria]); + if (0 == this->eng_list.Length()) { // no engine passed through the filter, invalidate the previously selected engine + this->sel_engine = INVALID_ENGINE; + } else if (!this->eng_list.Contains(this->sel_engine)) { // previously selected engine didn't pass the filter, select the first engine of the list + this->sel_engine = this->eng_list[0]; + } + } + + /** Filter a single engine */ + bool FilterSingleEngine(EngineID eid) + { + CargoID filter_type = this->cargo_filter[this->cargo_filter_criteria]; + return (filter_type == CF_ANY || CargoFilter(&eid, filter_type)); + } + + /* Figure out what train EngineIDs to put in the list */ + void GenerateBuildTrainList() + { + EngineID sel_id = INVALID_ENGINE; + int num_engines = 0; + int num_wagons = 0; + + this->filter.railtype = (this->listview_mode) ? RAILTYPE_END : GetRailType(this->window_number); + + this->eng_list.Clear(); + + /* Make list of all available train engines and wagons. + * Also check to see if the previously selected engine is still available, + * and if not, reset selection to INVALID_ENGINE. This could be the case + * when engines become obsolete and are removed */ + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { + EngineID eid = e->index; + const RailVehicleInfo *rvi = &e->u.rail; + + if (this->filter.railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue; + if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue; + + /* Filter now! So num_engines and num_wagons is valid */ + if (!FilterSingleEngine(eid)) continue; + + *this->eng_list.Append() = eid; + + if (rvi->railveh_type != RAILVEH_WAGON) { + num_engines++; + } else { + num_wagons++; + } + + if (eid == this->sel_engine) sel_id = eid; + } + + this->sel_engine = sel_id; + + /* make engines first, and then wagons, sorted by ListPositionOfEngine() */ + _internal_sort_order = false; + EngList_Sort(&this->eng_list, TrainEnginesThenWagonsSorter); + + /* and then sort engines */ + _internal_sort_order = this->descending_sort_order; + EngList_SortPartial(&this->eng_list, _sorter[0][this->sort_criteria], 0, num_engines); + + /* and finally sort wagons */ + EngList_SortPartial(&this->eng_list, _sorter[0][this->sort_criteria], num_engines, num_wagons); + } + + /* Generate the list of vehicles */ + void GenerateBuildList() + { + if (!this->eng_list.NeedRebuild()) return; + + this->GenerateBuildTrainList(); + this->eng_list.Compact(); + this->eng_list.RebuildDone(); + return; // trains should not reach the last sorting + + + this->FilterEngineList(); + + _internal_sort_order = this->descending_sort_order; + EngList_Sort(&this->eng_list, _sorter[this->vehicle_type][this->sort_criteria]); + + this->eng_list.Compact(); + this->eng_list.RebuildDone(); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_BV_SORT_ASCENDING_DESCENDING: + this->descending_sort_order ^= true; + _last_sort_order[this->vehicle_type] = this->descending_sort_order; + this->eng_list.ForceRebuild(); + this->SetDirty(); + break; + + case WID_BV_LIST: { + uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST); + size_t num_items = this->eng_list.Length(); + this->sel_engine = (i < num_items) ? this->eng_list[i] : INVALID_ENGINE; + this->SetDirty(); + if (click_count > 1 && !this->listview_mode) this->OnClick(pt, WID_BV_BUILD, 1); + break; + } + case WID_BV_SORT_DROPDOWN: { // Select sorting criteria dropdown menu + uint32 hidden_mask = 0; + /* Disable sorting by power or tractive effort when the original acceleration model for road vehicles is being used. */ + if (this->vehicle_type == VEH_ROAD && + _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) { + SetBit(hidden_mask, 3); // power + SetBit(hidden_mask, 4); // tractive effort + SetBit(hidden_mask, 8); // power by running costs + } + /* Disable sorting by tractive effort when the original acceleration model for trains is being used. */ + if (this->vehicle_type == VEH_TRAIN && + _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) { + SetBit(hidden_mask, 4); // tractive effort + } + ShowDropDownMenu(this, _sort_listing[this->vehicle_type], this->sort_criteria, WID_BV_SORT_DROPDOWN, 0, hidden_mask); + break; + } + + case WID_BV_CARGO_FILTER_DROPDOWN: // Select cargo filtering criteria dropdown menu + ShowDropDownMenu(this, this->cargo_filter_texts, this->cargo_filter_criteria, WID_BV_CARGO_FILTER_DROPDOWN, 0, 0); + break; + + case WID_BV_BUILD: { + EngineID sel_eng = this->sel_engine; + if (sel_eng != INVALID_ENGINE) { + Train *tmp = CmdBuildVirtualRailVehicle(sel_eng); + if (tmp) AddVirtualEngine(tmp); + } + break; + } + } + } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */ + if (this->vehicle_type == VEH_ROAD && + _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL && + this->sort_criteria > 7) { + this->sort_criteria = 0; + _last_sort_criteria[VEH_ROAD] = 0; + } + this->eng_list.ForceRebuild(); + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_BV_CAPTION: + if (this->vehicle_type == VEH_TRAIN && !this->listview_mode) { + const RailtypeInfo *rti = GetRailTypeInfo(this->filter.railtype); + SetDParam(0, rti->strings.build_caption); + } else { + SetDParam(0, (this->listview_mode ? STR_VEHICLE_LIST_AVAILABLE_TRAINS : STR_BUY_VEHICLE_TRAIN_ALL_CAPTION) + this->vehicle_type); + } + break; + + case WID_BV_SORT_DROPDOWN: + SetDParam(0, _sort_listing[this->vehicle_type][this->sort_criteria]); + break; + + case WID_BV_CARGO_FILTER_DROPDOWN: + SetDParam(0, this->cargo_filter_texts[this->cargo_filter_criteria]); + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_BV_LIST: + resize->height = GetEngineListHeight(this->vehicle_type); + size->height = 3 * resize->height; + break; + + case WID_BV_PANEL: + size->height = this->details_height; + break; + + case WID_BV_SORT_ASCENDING_DESCENDING: { + Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); + d.width += padding.width + WD_CLOSEBOX_WIDTH * 2; // Doubled since the string is centred and it also looks better. + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_BV_LIST: + DrawEngineList(this->vehicle_type, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, &this->eng_list, this->vscroll->GetPosition(), min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->eng_list.Length()), this->sel_engine, false, DEFAULT_GROUP); + break; + + case WID_BV_SORT_ASCENDING_DESCENDING: + this->DrawSortButtonState(WID_BV_SORT_ASCENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP); + break; + } + } + + virtual void OnPaint() + { + this->GenerateBuildList(); + this->vscroll->SetCount(this->eng_list.Length()); + + this->DrawWidgets(); + + if (!this->IsShaded()) { + int needed_height = this->details_height; + /* Draw details panels. */ + if (this->sel_engine != INVALID_ENGINE) { + NWidgetBase *nwi = this->GetWidget(WID_BV_PANEL); + int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT, + nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine); + needed_height = max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM); + } + if (needed_height != this->details_height) { // Details window are not high enough, enlarge them. + int resize = needed_height - this->details_height; + this->details_height = needed_height; + this->ReInit(0, resize); + return; + } + } + } + + virtual void OnQueryTextFinished(char *str) + { + if (str == NULL) return; + + DoCommandP(0, this->rename_engine, 0, CMD_RENAME_ENGINE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type), NULL, str); + } + + virtual void OnDropdownSelect(int widget, int index) + { + switch (widget) { + case WID_BV_SORT_DROPDOWN: + if (this->sort_criteria != index) { + this->sort_criteria = index; + _last_sort_criteria[this->vehicle_type] = this->sort_criteria; + this->eng_list.ForceRebuild(); + } + break; + + case WID_BV_CARGO_FILTER_DROPDOWN: // Select a cargo filter criteria + if (this->cargo_filter_criteria != index) { + this->cargo_filter_criteria = index; + _last_filter_criteria[this->vehicle_type] = this->cargo_filter[this->cargo_filter_criteria]; + /* deactivate filter if criteria is 'Show All', activate it otherwise */ + this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY); + this->eng_list.ForceRebuild(); + } + break; + } + this->SetDirty(); + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST); + this->GetWidget(WID_BV_LIST)->widget_data = (this->vscroll->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START); + } + + void AddVirtualEngine(Train *toadd) + { + if ( !*virtual_train ) { + *virtual_train = toadd; + } + else { + VehicleID target = (*(this->virtual_train))->GetLastUnit()->index; + CommandCost movec; + movec = CmdMoveRailVehicle(INVALID_TILE, DC_EXEC, (1<<21) | toadd->index, target, 0); + } + *noticeParent = true; + } +}; + +static WindowDesc _build_vehicle_desc( + WDP_AUTO, // window position + "template create virtual train",// const char* ini_key + 240, 268, // window size + WC_BUILD_VIRTUAL_TRAIN, // window class + WC_CREATE_TEMPLATE, // parent window class + WDF_CONSTRUCTION, // window flags + _nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets) // widgets + num widgets +); + +void ShowBuildVirtualTrainWindow(Train **vt, bool *noticeParent) +{ + // '0' as in VEH_TRAIN = Tile=0 + assert(IsCompanyBuildableVehicleType(VEH_TRAIN)); + + DeleteWindowById(WC_BUILD_VEHICLE, 0); + + new BuildVirtualTrainWindow(&_build_vehicle_desc, vt, noticeParent); +} diff --git a/src/tbtr_template_gui_create_virtualtrain.h b/src/tbtr_template_gui_create_virtualtrain.h new file mode 100644 index 0000000000..d454f74069 --- /dev/null +++ b/src/tbtr_template_gui_create_virtualtrain.h @@ -0,0 +1,8 @@ +#ifndef BUILD_VIRTUAL_TRAIN_GUI +#define BUILD_VIRTUAL_TRAIN_GUI + +#include "train.h" + +void ShowBuildVirtualTrainWindow(Train**, bool*); + +#endif diff --git a/src/tbtr_template_gui_main.cpp b/src/tbtr_template_gui_main.cpp new file mode 100644 index 0000000000..5bd39c517a --- /dev/null +++ b/src/tbtr_template_gui_main.cpp @@ -0,0 +1,692 @@ +// mygui.c + + +//#include "tbtr_mygui.h" +#include +#include + + +#include "stdafx.h" +#include "command_func.h" +#include "vehicle_gui.h" +#include "newgrf_engine.h" +#include "group.h" +#include "rail.h" +#include "strings_func.h" +#include "window_func.h" +#include "autoreplace_func.h" +#include "company_func.h" +#include "engine_base.h" +#include "window_gui.h" +#include "viewport_func.h" +#include "tilehighlight_func.h" +#include "engine_gui.h" +#include "settings_func.h" +#include "core/geometry_func.hpp" +#include "rail_gui.h" + +#include "table/sprites.h" +#include "table/strings.h" + +// test creating pool -> creating vehicles +#include "core/pool_func.hpp" + +#include "vehicle_gui_base.h" +#include "vehicle_base.h" +#include "train.h" +#include "vehicle_func.h" + +#include "gfx_type.h" + +#include "engine_func.h" + +// drawing the vehicle length based on occupied tiles +#include "spritecache.h" + +#include "tbtr_template_gui_main.h" +#include "tbtr_template_gui_create.h" +#include "tbtr_template_vehicle.h" +//#include "tbtr_template_vehicle_func.h" + + +typedef GUIList GUIGroupList; + +enum TemplateReplaceWindowWidgets { + TRW_CAPTION, + + TRW_WIDGET_INSET_GROUPS, + TRW_WIDGET_TOP_MATRIX, + TRW_WIDGET_TOP_SCROLLBAR, + + TRW_WIDGET_INSET_TEMPLATES, + TRW_WIDGET_BOTTOM_MATRIX, + TRW_WIDGET_BOTTOM_SCROLLBAR, + + TRW_WIDGET_TMPL_INFO_INSET, + TRW_WIDGET_TMPL_INFO_PANEL, + + TRW_WIDGET_TMPL_PRE_BUTTON_FLUFF, + + TRW_WIDGET_TMPL_BUTTONS_CONFIGTMPL_REUSE, + TRW_WIDGET_TMPL_BUTTONS_CONFIGTMPL_KEEP, + TRW_WIDGET_TMPL_BUTTONS_CONFIGTMPL_REFIT, + TRW_WIDGET_TMPL_BUTTONS_CONFIG_RIGHTPANEL, + + TRW_WIDGET_TMPL_BUTTONS_DEFINE, + TRW_WIDGET_TMPL_BUTTONS_EDIT, + TRW_WIDGET_TMPL_BUTTONS_CLONE, + TRW_WIDGET_TMPL_BUTTONS_DELETE, + TRW_WIDGET_TMPL_BUTTONS_RPLALL, + TRW_WIDGET_TMPL_BUTTON_FLUFF, + TRW_WIDGET_TMPL_BUTTONS_EDIT_RIGHTPANEL, + + TRW_WIDGET_TITLE_INFO_GROUP, + TRW_WIDGET_TITLE_INFO_TEMPLATE, + + TRW_WIDGET_INFO_GROUP, + TRW_WIDGET_INFO_TEMPLATE, + + TRW_WIDGET_TMPL_BUTTONS_SPACER, + + TRW_WIDGET_START, + TRW_WIDGET_TRAIN_FLUFF_LEFT, + TRW_WIDGET_TRAIN_RAILTYPE_DROPDOWN, + TRW_WIDGET_TRAIN_FLUFF_RIGHT, + TRW_WIDGET_STOP, + + TRW_WIDGET_SEL_TMPL_DISPLAY_CREATE, +}; + +static const NWidgetPart _widgets[] = { + // Title bar + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, TRW_CAPTION), SetDataTip(STR_TMPL_RPL_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + //Top Matrix + NWidget(NWID_VERTICAL), + NWidget(WWT_INSET, COLOUR_GREY, TRW_WIDGET_INSET_GROUPS), SetMinimalSize(216,12), SetDataTip(STR_TMPL_MAINGUI_DEFINEDGROUPS, STR_TMPL_MAINGUI_DEFINEDGROUPS), SetResize(1, 0), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, TRW_WIDGET_TOP_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetDataTip(0x1, STR_REPLACE_HELP_LEFT_ARRAY), SetResize(1, 0), SetScrollbar(TRW_WIDGET_TOP_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, TRW_WIDGET_TOP_SCROLLBAR), + EndContainer(), + EndContainer(), + // Template Display + NWidget(NWID_VERTICAL), + NWidget(WWT_INSET, COLOUR_GREY, TRW_WIDGET_INSET_TEMPLATES), SetMinimalSize(216,12), SetDataTip(STR_TMPL_AVAILABLE_TEMPLATES, STR_TMPL_AVAILABLE_TEMPLATES), SetResize(1, 0), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, TRW_WIDGET_BOTTOM_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetDataTip(0x1, STR_REPLACE_HELP_RIGHT_ARRAY), SetResize(1, 1), SetScrollbar(TRW_WIDGET_BOTTOM_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, TRW_WIDGET_BOTTOM_SCROLLBAR), + EndContainer(), + EndContainer(), + // Info Area + NWidget(NWID_VERTICAL), + NWidget(WWT_INSET, COLOUR_GREY, TRW_WIDGET_TMPL_INFO_INSET), SetMinimalSize(216,12), SetResize(1,0), SetDataTip(STR_TMPL_AVAILABLE_TEMPLATES, STR_TMPL_AVAILABLE_TEMPLATES), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, TRW_WIDGET_TMPL_INFO_PANEL), SetMinimalSize(216,50), SetResize(1,0), EndContainer(), + EndContainer(), + // Control Area + NWidget(NWID_VERTICAL), + // Spacing + NWidget(WWT_INSET, COLOUR_GREY, TRW_WIDGET_TMPL_PRE_BUTTON_FLUFF), SetMinimalSize(139, 12), SetResize(1,0), EndContainer(), + // Config buttons + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_CONFIGTMPL_REUSE), SetMinimalSize(150,12), SetResize(0,0), SetDataTip(STR_TMPL_SET_USEDEPOT, STR_TMPL_SET_USEDEPOT_TIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_CONFIGTMPL_KEEP), SetMinimalSize(150,12), SetResize(0,0), SetDataTip(STR_TMPL_SET_KEEPREMAINDERS, STR_TMPL_SET_KEEPREMAINDERS_TIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_CONFIGTMPL_REFIT), SetMinimalSize(150,12), SetResize(0,0), SetDataTip(STR_TMPL_SET_REFIT, STR_TMPL_SET_REFIT_TIP), + NWidget(WWT_PANEL, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_CONFIG_RIGHTPANEL), SetMinimalSize(12,12), SetResize(1,0), EndContainer(), + EndContainer(), + // Edit buttons + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_DEFINE), SetMinimalSize(75,12), SetResize(0,0), SetDataTip(STR_TMPL_DEFINE_TEMPLATE, STR_REPLACE_ENGINE_WAGON_SELECT_HELP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_EDIT), SetMinimalSize(75,12), SetResize(0,0), SetDataTip(STR_TMPL_EDIT_TEMPLATE, STR_REPLACE_ENGINE_WAGON_SELECT_HELP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_CLONE), SetMinimalSize(75,12), SetResize(0,0), SetDataTip(STR_TMPL_CREATE_CLONE_VEH, STR_REPLACE_ENGINE_WAGON_SELECT_HELP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_DELETE), SetMinimalSize(75,12), SetResize(0,0), SetDataTip(STR_TMPL_DELETE_TEMPLATE, STR_REPLACE_ENGINE_WAGON_SELECT_HELP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_RPLALL), SetMinimalSize(150,12), SetResize(0,0), SetDataTip(STR_TMPL_RPL_ALL_TMPL, STR_REPLACE_ENGINE_WAGON_SELECT_HELP), + NWidget(WWT_PANEL, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_EDIT_RIGHTPANEL), SetMinimalSize(50,12), SetResize(1,0), EndContainer(), + EndContainer(), + EndContainer(), + // Start/Stop buttons + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TRW_WIDGET_START), SetMinimalSize(150, 12), SetDataTip(STR_TMPL_RPL_START, STR_REPLACE_ENGINE_WAGON_SELECT_HELP), + NWidget(WWT_PANEL, COLOUR_GREY, TRW_WIDGET_TRAIN_FLUFF_LEFT), SetMinimalSize(15, 12), EndContainer(), + NWidget(WWT_DROPDOWN, COLOUR_GREY, TRW_WIDGET_TRAIN_RAILTYPE_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(0x0, STR_REPLACE_HELP_RAILTYPE), SetResize(1, 0), + NWidget(WWT_PANEL, COLOUR_GREY, TRW_WIDGET_TRAIN_FLUFF_RIGHT), SetMinimalSize(16, 12), EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TRW_WIDGET_STOP), SetMinimalSize(150, 12), SetDataTip(STR_TMPL_RPL_STOP, STR_REPLACE_REMOVE_WAGON_HELP), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + +static WindowDesc _replace_rail_vehicle_desc( + WDP_AUTO, + "template replace window", + 456, 156, + WC_TEMPLATEGUI_MAIN, + WC_NONE, // parent window class + WDF_CONSTRUCTION, + _widgets, lengthof(_widgets) +); + +class TemplateReplaceWindow : public Window { +private: + + GUIGroupList groups; ///< List of groups + byte unitnumber_digits; + + short line_height; + short matrixContentLeftMargin; + + int details_height; ///< Minimal needed height of the details panels (found so far). + RailType sel_railtype; ///< Type of rail tracks selected. + Scrollbar *vscroll[2]; + // listing/sorting continued + GUITemplateList templates; + GUITemplateList::SortFunction **template_sorter_funcs; + + short selected_template_index; + short selected_group_index; + + bool templateNotice; + bool editInProgress; + +public: + TemplateReplaceWindow(WindowDesc *wdesc, byte dig, int step_h) : Window(wdesc) + { + // listing/sorting + templates.SetSortFuncs(this->template_sorter_funcs); + + // From BaseVehicleListWindow + this->unitnumber_digits = dig; + + this->sel_railtype = RAILTYPE_BEGIN; + this->details_height = 10 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + + this->line_height = step_h; + + this->CreateNestedTree(wdesc); + this->vscroll[0] = this->GetScrollbar(TRW_WIDGET_TOP_SCROLLBAR); + this->vscroll[1] = this->GetScrollbar(TRW_WIDGET_BOTTOM_SCROLLBAR); + this->vscroll[0]->SetStepSize(step_h / 2); + this->vscroll[1]->SetStepSize(step_h); + this->FinishInitNested(VEH_TRAIN); + + this->owner = _local_company; + + this->groups.ForceRebuild(); + this->groups.NeedResort(); + this->BuildGroupList(_local_company); + this->groups.Sort(&GroupNameSorter); + + + this->matrixContentLeftMargin = 40; + this->selected_template_index = -1; + this->selected_group_index = -1; + + this->templateNotice = false; + this->editInProgress = false; + + this->templates.ForceRebuild(); + + BuildTemplateGuiList(&this->templates, this->vscroll[1], this->owner, this->sel_railtype); + } + + ~TemplateReplaceWindow() { + DeleteWindowById(WC_CREATE_TEMPLATE, this->window_number); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case TRW_WIDGET_TOP_MATRIX: + resize->height = GetVehicleListHeight(VEH_TRAIN, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP) / 2; + size->height = 8 * resize->height; + break; + case TRW_WIDGET_BOTTOM_MATRIX: + resize->height = GetVehicleListHeight(VEH_TRAIN, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP); + size->height = 4 * resize->height; + break; + case TRW_WIDGET_TRAIN_RAILTYPE_DROPDOWN: { + Dimension d = {0, 0}; + for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { + const RailtypeInfo *rti = GetRailTypeInfo(rt); + // Skip rail type if it has no label + if (rti->label == 0) continue; + d = maxdim(d, GetStringBoundingBox(rti->strings.replace_text)); + } + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + } + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case TRW_CAPTION: + SetDParam(0, STR_TMPL_RPL_TITLE); + break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case TRW_WIDGET_TOP_MATRIX: { + DrawAllGroupsFunction(this->line_height, r); + break; + } + case TRW_WIDGET_BOTTOM_MATRIX: { + DrawTemplateList(this->line_height, r); + break; + } + case TRW_WIDGET_TMPL_INFO_PANEL: { + DrawTemplateInfo(this->line_height, r); + break; + } + } + } + + virtual void OnPaint() + { + BuildTemplateGuiList(&this->templates, this->vscroll[1], this->owner, this->sel_railtype); + + this->BuildGroupList(_local_company); + this->groups.Sort(&GroupNameSorter); + + if ( templateNotice ) { + BuildTemplateGuiList(&this->templates, vscroll[1], _local_company, this->sel_railtype); + templateNotice = false; + this->SetDirty(); + } + /* sets the colour of that art thing */ + this->GetWidget(TRW_WIDGET_TRAIN_FLUFF_LEFT)->colour = _company_colours[_local_company]; + this->GetWidget(TRW_WIDGET_TRAIN_FLUFF_RIGHT)->colour = _company_colours[_local_company]; + + /* Show the selected railtype in the pulldown menu */ + this->GetWidget(TRW_WIDGET_TRAIN_RAILTYPE_DROPDOWN)->widget_data = GetRailTypeInfo(sel_railtype)->strings.replace_text; + + this->DrawWidgets(); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + if ( this->editInProgress ) return; + + switch (widget) { + case TRW_WIDGET_TMPL_BUTTONS_CONFIGTMPL_REUSE: { + if ( this->selected_template_index >= 0 ) { + TemplateVehicle *sel = TemplateVehicle::Get(((this->templates)[selected_template_index])->index); + sel->ToggleReuseDepotVehicles(); + } + break; + } + case TRW_WIDGET_TMPL_BUTTONS_CONFIGTMPL_KEEP: { + if ( this->selected_template_index >= 0 ) { + TemplateVehicle *sel = TemplateVehicle::Get(((this->templates)[selected_template_index])->index); + sel->ToggleKeepRemainingVehicles(); + } + break; + } + case TRW_WIDGET_TMPL_BUTTONS_CONFIGTMPL_REFIT: { + if ( this->selected_template_index >= 0 ) { + TemplateVehicle *sel = TemplateVehicle::Get(((this->templates)[selected_template_index])->index); + sel->ToggleRefitAsTemplate(); + } + break; + } + case TRW_WIDGET_TMPL_BUTTONS_DEFINE: + ShowTemplateCreateWindow(0, &templateNotice, &editInProgress, this->line_height); + break; + case TRW_WIDGET_TMPL_BUTTONS_EDIT: { + if ( this->selected_template_index >= 0 ) { + editInProgress = true; + TemplateVehicle *sel = TemplateVehicle::Get(((this->templates)[selected_template_index])->index); + ShowTemplateCreateWindow(sel, &templateNotice, &editInProgress, this->line_height); + } + break; + } + case TRW_WIDGET_TMPL_BUTTONS_CLONE: { + this->SetWidgetDirty(TRW_WIDGET_TMPL_BUTTONS_CLONE); + this->ToggleWidgetLoweredState(TRW_WIDGET_TMPL_BUTTONS_CLONE); + + if (this->IsWidgetLowered(TRW_WIDGET_TMPL_BUTTONS_CLONE)) { + static const CursorID clone_icon = SPR_CURSOR_CLONE_TRAIN; + SetObjectToPlaceWnd(clone_icon, PAL_NONE, HT_VEHICLE, this); + } else { + ResetObjectToPlace(); + } + break; + } + case TRW_WIDGET_TMPL_BUTTONS_DELETE: + if ( selected_template_index >= 0 && !editInProgress ) { + // identify template to delete + TemplateVehicle *del = TemplateVehicle::Get(((this->templates)[selected_template_index])->index); + // remove a corresponding template replacement if existing + TemplateReplacement *tr = GetTemplateReplacementByTemplateID(del->index); + if ( tr ) { + delete tr; + } + delete del; + BuildTemplateGuiList(&this->templates, this->vscroll[1], this->owner, this->sel_railtype); + selected_template_index = -1; + } + break; + case TRW_WIDGET_TMPL_BUTTONS_RPLALL: { + ShowTemplateReplaceAllGui(); + break; + } + case TRW_WIDGET_TRAIN_RAILTYPE_DROPDOWN: // Railtype selection dropdown menu + ShowDropDownList(this, GetRailTypeDropDownList(true), sel_railtype, TRW_WIDGET_TRAIN_RAILTYPE_DROPDOWN); + break; + case TRW_WIDGET_TOP_MATRIX: { + uint16 newindex = (uint16)((pt.y - this->nested_array[TRW_WIDGET_TOP_MATRIX]->pos_y) / (this->line_height/2) ) + this->vscroll[0]->GetPosition(); + if ( newindex == this->selected_group_index || newindex >= this->groups.Length() ) { + this->selected_group_index = -1; + } + else if ( newindex < this->groups.Length() ) { + this->selected_group_index = newindex; + } + break; + } + case TRW_WIDGET_BOTTOM_MATRIX: { + uint16 newindex = (uint16)((pt.y - this->nested_array[TRW_WIDGET_BOTTOM_MATRIX]->pos_y) / this->line_height) + this->vscroll[1]->GetPosition(); + if ( newindex == this->selected_template_index || newindex >= templates.Length() ) { + this->selected_template_index = -1; + } + else if ( newindex < templates.Length() ) { + this->selected_template_index = newindex; + } + break; + } + case TRW_WIDGET_START: { + if ( this->selected_template_index >= 0 && this->selected_group_index >= 0) { + uint32 tv_index = ((this->templates)[selected_template_index])->index; + int current_group_index = (this->groups)[this->selected_group_index]->index; + IssueTemplateReplacement(current_group_index, tv_index); + } + break; + } + case TRW_WIDGET_STOP: + if ( this->selected_group_index == -1 ) + return; + int current_group_index = (this->groups)[this->selected_group_index]->index; + TemplateReplacement *tr = GetTemplateReplacementByGroupID(current_group_index); + if ( tr ) + delete tr; + break; + } + this->SetDirty(); + } + + virtual bool OnVehicleSelect(const Vehicle *v) + { + // create a new template from the clicked vehicle + TemplateVehicle *tv = CloneTemplateVehicleFromTrain((const Train*)v); + if ( !tv ) return false; + + BuildTemplateGuiList(&this->templates, vscroll[1], _local_company, this->sel_railtype); + this->ToggleWidgetLoweredState(TRW_WIDGET_TMPL_BUTTONS_CLONE); + ResetObjectToPlace(); + this->SetDirty(); + + return true; + } + + virtual void OnDropdownSelect(int widget, int index) + { + RailType temp = (RailType)index; + if (temp == this->sel_railtype) return; // we didn't select a new one. No need to change anything + this->sel_railtype = temp; + /* Reset scrollbar positions */ + this->vscroll[0]->SetPosition(0); + this->vscroll[1]->SetPosition(0); + BuildTemplateGuiList(&this->templates, this->vscroll[1], this->owner, this->sel_railtype); + this->SetDirty(); + } + + virtual void OnResize() + { + /* Top Matrix */ + NWidgetCore *nwi = this->GetWidget(TRW_WIDGET_TOP_MATRIX); + this->vscroll[0]->SetCapacityFromWidget(this, TRW_WIDGET_TOP_MATRIX); + nwi->widget_data = (this->vscroll[0]->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START); + /* Bottom Matrix */ + NWidgetCore *nwi2 = this->GetWidget(TRW_WIDGET_BOTTOM_MATRIX); + this->vscroll[1]->SetCapacityFromWidget(this, TRW_WIDGET_BOTTOM_MATRIX); + nwi2->widget_data = (this->vscroll[1]->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START); + } + + virtual void OnTick() + { + if ( templateNotice ) { + BuildTemplateGuiList(&this->templates, this->vscroll[1], this->owner, this->sel_railtype); + this->SetDirty(); + templateNotice = false; + } + + } + + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + this->groups.ForceRebuild(); + this->templates.ForceRebuild(); + } + + /** For a given group (id) find the template that is issued for template replacement for this group and return this template's index + * from the gui list */ + short FindTemplateIndexForGroup(short gid) const + { + TemplateReplacement *tr = GetTemplateReplacementByGroupID(gid); + if ( !tr ) + return -1; + + for ( uint32 i=0; itemplates.Length(); ++i ) + if ( templates[i]->index == tr->sel_template ) + return i; + return -1; + } + + /** Sort the groups by their name */ + static int CDECL GroupNameSorter(const Group * const *a, const Group * const *b) + { + static const Group *last_group[2] = { NULL, NULL }; + static char last_name[2][64] = { "", "" }; + + if (*a != last_group[0]) { + last_group[0] = *a; + SetDParam(0, (*a)->index); + GetString(last_name[0], STR_GROUP_NAME, lastof(last_name[0])); + } + + if (*b != last_group[1]) { + last_group[1] = *b; + SetDParam(0, (*b)->index); + GetString(last_name[1], STR_GROUP_NAME, lastof(last_name[1])); + } + + int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). + if (r == 0) return (*a)->index - (*b)->index; + return r; + } + + void BuildGroupList(Owner owner) + { + if (!this->groups.NeedRebuild()) { + return; + } + this->groups.Clear(); + + const Group *g; + FOR_ALL_GROUPS(g) { + if (g->owner == owner ) { + *this->groups.Append() = g; + } + } + + this->groups.Compact(); + this->groups.RebuildDone(); + this->vscroll[0]->SetCount(groups.Length()); + } + + void DrawAllGroupsFunction(int line_height, const Rect &r) const + { + int left = r.left + WD_MATRIX_LEFT; + int right = r.right - WD_MATRIX_RIGHT; + int y = r.top; + int max = min(this->vscroll[0]->GetPosition() + this->vscroll[0]->GetCapacity(), this->groups.Length()); + + /* Then treat all groups defined by/for the current company */ + for ( int i=this->vscroll[0]->GetPosition(); igroups)[i]; + short g_id = g->index; + + /* Fill the background of the current cell in a darker tone for the currently selected template */ + if ( this->selected_group_index == i ) { + GfxFillRect(left, y, right, y+(this->line_height)/2, _colour_gradient[COLOUR_GREY][3]); + } + + SetDParam(0, g_id); + StringID str = STR_GROUP_NAME; + DrawString(left+30, right, y+2, str, TC_BLACK); + + /* Draw the template in use for this group, if there is one */ + short template_in_use = FindTemplateIndexForGroup(g_id); + if ( template_in_use >= 0 ) { + SetDParam(0, template_in_use); + DrawString ( left, right, y+2, STR_TMPL_GROUP_USES_TEMPLATE, TC_BLACK, SA_HOR_CENTER); + } + /* If there isn't a template applied from the current group, check if there is one for another rail type */ + else if ( GetTemplateReplacementByGroupID(g_id) ) { + DrawString ( left, right, y+2, STR_TMPL_TMPLRPL_EX_DIFF_RAILTYPE, TC_SILVER, SA_HOR_CENTER); + } + + /* Draw the number of trains that still need to be treated by the currently selected template replacement */ + TemplateReplacement *tr = GetTemplateReplacementByGroupID(g_id); + if ( tr ) { + TemplateVehicle *tv = TemplateVehicle::Get(tr->sel_template); + int num_trains = NumTrainsNeedTemplateReplacement(g_id, tv); + // Draw text + TextColour color = TC_GREY; + if ( num_trains ) color = TC_BLACK; + DrawString(left, right-16, y+2, STR_TMPL_NUM_TRAINS_NEED_RPL, color, SA_RIGHT); + // Draw number + if ( num_trains ) color = TC_ORANGE; + else color = TC_GREY; + SetDParam(0, num_trains); + DrawString(left, right-4, y+2, STR_JUST_INT, color, SA_RIGHT); + } + + y+=line_height / 2; + } + } + + void DrawTemplateList(int line_height, const Rect &r) const + { + int left = r.left; + int right = r.right; + int y = r.top; + + Scrollbar *draw_vscroll = vscroll[1]; + uint max = min(draw_vscroll->GetPosition() + draw_vscroll->GetCapacity(), this->templates.Length()); + + const TemplateVehicle *v; + for ( uint i = draw_vscroll->GetPosition(); i < max; ++i) { + + v = (this->templates)[i]; + + /* Fill the background of the current cell in a darker tone for the currently selected template */ + if ( this->selected_template_index == (int32)i ) { + GfxFillRect(left, y, right, y+this->line_height, _colour_gradient[COLOUR_GREY][3]); + } + + /* Draw a notification string for chains that are not runnable */ + if ( v->IsFreeWagonChain() ) { + DrawString(left, right-2, y+line_height-FONT_HEIGHT_SMALL-WD_FRAMERECT_BOTTOM - 2, STR_TMPL_WARNING_FREE_WAGON, TC_RED, SA_RIGHT); + } + + /* Draw the template's length in tile-units */ + SetDParam(0, v->GetRealLength()); + SetDParam(1, 1); + DrawString(left, right-4, y+2, STR_TINY_BLACK_DECIMAL, TC_BLACK, SA_RIGHT); + + /* Draw the template */ + DrawTemplate(v, left+50, right, y); + + /* Buying cost */ + SetDParam(0, CalculateOverallTemplateCost(v)); + DrawString(left+35, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_TEMPLATE_OVR_VALUE_notinyfont, TC_BLUE, SA_LEFT); + + /* Index of current template vehicle in the list of all templates for its company */ + SetDParam(0, i); + DrawString(left+5, left+25, y + line_height/2, STR_BLACK_INT, TC_BLACK, SA_RIGHT); + + /* Draw whether the current template is in use by any group */ + if ( v->NumGroupsUsingTemplate() > 0 ) { + DrawString(left+200, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMP_TEMPLATE_IN_USE, TC_GREEN, SA_LEFT); + } + + /* Draw information about template configuration settings */ + TextColour color; + if ( v->IsSetReuseDepotVehicles() ) color = TC_LIGHT_BLUE; + else color = TC_GREY; + DrawString(left+200, right, y+2, STR_TMPL_CONFIG_USEDEPOT, color, SA_LEFT); + if ( v->IsSetKeepRemainingVehicles() ) color = TC_LIGHT_BLUE; + else color = TC_GREY; + DrawString(left+275, right, y+2, STR_TMPL_CONFIG_KEEPREMAINDERS, color, SA_LEFT); + if ( v->IsSetRefitAsTemplate() ) color = TC_LIGHT_BLUE; + else color = TC_GREY; + DrawString(left+350, right, y+2, STR_TMPL_CONFIG_REFIT, color, SA_LEFT); + + y += line_height; + } + } + + void DrawTemplateInfo(int line_height, const Rect &r) const + { + if ( this->selected_template_index == -1 || (short)this->templates.Length() <= this->selected_template_index ) + return; + + const TemplateVehicle *tmp = this->templates[this->selected_template_index]; + + /* Draw vehicle performance info */ + SetDParam(2, tmp->max_speed); + SetDParam(1, tmp->power); + SetDParam(0, tmp->weight); + SetDParam(3, tmp->max_te); + DrawString(r.left+8, r.right, r.top+4, STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE); + + /* Draw cargo summary */ + short top = r.top + 24; + short left = r.left + 8; + short count_rows = 0; + short max_rows = 2; + + CargoArray cargo_caps; + for ( ; tmp; tmp=tmp->Next() ) + cargo_caps[tmp->cargo_type] += tmp->cargo_cap; + int y = top; + for (CargoID i = 0; i < NUM_CARGO; ++i) { + if ( cargo_caps[i] > 0 ) { + count_rows++; + SetDParam(0, i); + SetDParam(1, cargo_caps[i]); + SetDParam(2, _settings_game.vehicle.freight_trains); + DrawString(left, r.right, y, FreightWagonMult(i) > 1 ? STR_TMPL_CARGO_SUMMARY_MULTI : STR_TMPL_CARGO_SUMMARY, TC_WHITE, SA_LEFT); + y += this->line_height/2; + if ( count_rows % max_rows == 0 ) { + y = top; + left += 150; + } + } + } + } +}; + +void ShowTemplateReplaceWindow(byte dig, int step_h) +{ + new TemplateReplaceWindow(&_replace_rail_vehicle_desc, dig, step_h); +} + diff --git a/src/tbtr_template_gui_main.h b/src/tbtr_template_gui_main.h new file mode 100644 index 0000000000..69e68d56d8 --- /dev/null +++ b/src/tbtr_template_gui_main.h @@ -0,0 +1,20 @@ +// _template_gui_main.h + +#ifndef TEMPLATE_GUI_H +#define TEMPLATE_GUI_H + +#include "engine_type.h" +#include "group_type.h" +#include "vehicle_type.h" +#include "string_func.h" +#include "strings_func.h" + +#include "tbtr_template_vehicle.h" +#include "tbtr_template_vehicle_func.h" +#include "tbtr_template_gui_replaceall.h" + +typedef GUIList GUIGroupList; + +void ShowTemplateReplaceWindow(byte, int); + +#endif diff --git a/src/tbtr_template_gui_replaceall.cpp b/src/tbtr_template_gui_replaceall.cpp new file mode 100644 index 0000000000..51b8cea4db --- /dev/null +++ b/src/tbtr_template_gui_replaceall.cpp @@ -0,0 +1,517 @@ +// replace all gui impl + +#include "tbtr_template_gui_replaceall.h" + +#include + +/* + * A wrapper which contains a virtual train and additional info of the template vehicle it is replacing + * We will restore this additional info when creating a new template from the changed virtual train + */ +struct VirtTrainInfo { + // the virtual train + Train *vt; + + // additional info from the template + VehicleID original_index; + + bool reuse_depot_vehicles, + keep_remaining_vehicles, + refit_as_template; + + CargoID cargo_type; + byte cargo_subtype; + + // a fancy constructor + VirtTrainInfo(Train *t) { this->vt = t; } +}; + +typedef AutoFreeSmallVector VirtTrainList; +enum Widgets { + RPLALL_GUI_CAPTION, + + RPLALL_GUI_INSET_1, + RPLALL_GUI_INSET_1_1, + RPLALL_GUI_INSET_1_2, + RPLALL_GUI_MATRIX_TOPLEFT, + RPLALL_GUI_MATRIX_TOPRIGHT, + RPLALL_GUI_SCROLL_TL, + RPLALL_GUI_SCROLL_TR, + + RPLALL_GUI_INSET_2, + RPLALL_GUI_MATRIX_BOTTOM, + RPLALL_GUI_SCROLL_BO, + + RPLALL_GUI_INSET_3, + RPLALL_GUI_BUTTON_RPLALL, + RPLALL_GUI_PANEL_BUTTONFLUFF_1, + RPLALL_GUI_PANEL_BUTTONFLUFF_2, + RPLALL_GUI_BUTTON_APPLY, + RPLALL_GUI_PANEL_BUTTONFLUFF_3, + RPLALL_GUI_BUTTON_CANCEL, + + RPLALL_GUI_PANEL_RESIZEFLUFF +}; + +static const NWidgetPart widgets[] = { + // title bar + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, RPLALL_GUI_CAPTION), SetDataTip(STR_TMPL_RPLALLGUI_TITLE, STR_TMPL_RPLALLGUI_TITLE), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + // top matrices + NWidget(WWT_INSET, COLOUR_GREY, RPLALL_GUI_INSET_1), SetMinimalSize(100,12), SetResize(1,0), SetDataTip(STR_TMPL_RPLALLGUI_INSET_TOP, STR_TMPL_RPLALLGUI_INSET_TOP), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_VERTICAL), + NWidget(WWT_INSET, COLOUR_GREY, RPLALL_GUI_INSET_1_1), SetMinimalSize(100,12), SetResize(1,0), SetDataTip(STR_TMPL_RPLALLGUI_INSET_TOP_1, STR_TMPL_RPLALLGUI_INSET_TOP_1), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, RPLALL_GUI_MATRIX_TOPLEFT), SetMinimalSize(100, 16), SetFill(1, 1), SetResize(1, 1), SetScrollbar(RPLALL_GUI_SCROLL_TL),// SetDataTip(0x1, STR_REPLACE_HELP_LEFT_ARRAY), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, RPLALL_GUI_SCROLL_TL), + EndContainer(), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(WWT_INSET, COLOUR_GREY, RPLALL_GUI_INSET_1_2), SetMinimalSize(100,12), SetResize(1,0), SetDataTip(STR_TMPL_RPLALLGUI_INSET_TOP_2, STR_TMPL_RPLALLGUI_INSET_TOP_2), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, RPLALL_GUI_MATRIX_TOPRIGHT), SetMinimalSize(100, 16), SetFill(1, 1), SetResize(1, 1), SetScrollbar(RPLALL_GUI_SCROLL_TR),// SetDataTip(0x1, STR_REPLACE_HELP_LEFT_ARRAY), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, RPLALL_GUI_SCROLL_TR), + EndContainer(), + EndContainer(), + EndContainer(), + // bottom matrix + NWidget(WWT_INSET, COLOUR_GREY, RPLALL_GUI_INSET_2), SetMinimalSize(200,12), SetResize(1,0), SetDataTip(STR_TMPL_RPLALLGUI_INSET_BOTTOM, STR_TMPL_RPLALLGUI_INSET_BOTTOM), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, RPLALL_GUI_MATRIX_BOTTOM), SetMinimalSize(200, 16), SetFill(1, 1), SetResize(1, 1), SetScrollbar(RPLALL_GUI_SCROLL_BO),// SetDataTip(0x1, STR_REPLACE_HELP_LEFT_ARRAY), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, RPLALL_GUI_SCROLL_BO), + EndContainer(), + // control area + NWidget(WWT_INSET, COLOUR_GREY, RPLALL_GUI_INSET_3), SetMinimalSize(200,12), SetResize(1,0), EndContainer(),// SetDataTip(STR_TMPL_MAINGUI_DEFINEDGROUPS, STR_TMPL_MAINGUI_DEFINEDGROUPS), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_GREY, RPLALL_GUI_PANEL_BUTTONFLUFF_1), SetMinimalSize(75,12), SetResize(1,0), EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, RPLALL_GUI_BUTTON_RPLALL), SetMinimalSize(150,12), SetResize(0,0), SetDataTip(STR_TMPL_RPLALLGUI_BUTTON_RPLALL, STR_TMPL_RPLALLGUI_BUTTON_RPLALL), + NWidget(WWT_PANEL, COLOUR_GREY, RPLALL_GUI_PANEL_BUTTONFLUFF_2), SetMinimalSize(75,12), SetResize(1,0), EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, RPLALL_GUI_BUTTON_APPLY), SetMinimalSize(75,12), SetResize(1,0), SetDataTip(STR_TMPL_RPLALLGUI_BUTTON_APPLY, STR_TMPL_RPLALLGUI_BUTTON_APPLY), + NWidget(WWT_PANEL, COLOUR_GREY, RPLALL_GUI_PANEL_BUTTONFLUFF_3), SetMinimalSize(150,12), SetResize(0,0), EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, RPLALL_GUI_BUTTON_CANCEL), SetMinimalSize(75,12), SetResize(1,0), SetDataTip(STR_TMPL_RPLALLGUI_BUTTON_CANCEL, STR_TMPL_RPLALLGUI_BUTTON_CANCEL), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_GREY, RPLALL_GUI_PANEL_RESIZEFLUFF), SetMinimalSize(100,12), SetResize(1,0), EndContainer(), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + +static WindowDesc _template_replace_replaceall_desc( + WDP_AUTO, + "template replace window", + 400, 200, + WC_TEMPLATEGUI_RPLALL, WC_NONE, + WDF_CONSTRUCTION, + widgets, lengthof(widgets) +); + +static int CDECL EngineNumberSorter(const EngineID *a, const EngineID *b) +{ + int r = Engine::Get(*a)->list_position - Engine::Get(*b)->list_position; + + return r; +} +static int CDECL TrainEnginesThenWagonsSorter(const EngineID *a, const EngineID *b) +{ + int val_a = (RailVehInfo(*a)->railveh_type == RAILVEH_WAGON ? 1 : 0); + int val_b = (RailVehInfo(*b)->railveh_type == RAILVEH_WAGON ? 1 : 0); + int r = val_a - val_b; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return r; +} + + +class TemplateReplacementReplaceAllWindow : public Window { +private: + uint16 line_height; + Scrollbar *vscroll_tl, + *vscroll_tr, + *vscroll_bo; + GUIEngineList *engines_left, + *engines_right; + short selected_left, + selected_right; + VirtTrainList *virtualTrains; + +public: + TemplateReplacementReplaceAllWindow(WindowDesc *wdesc) : Window(wdesc) + { + + this->CreateNestedTree(wdesc); + + this->vscroll_tl = this->GetScrollbar(RPLALL_GUI_SCROLL_TL); + this->vscroll_tr = this->GetScrollbar(RPLALL_GUI_SCROLL_TR); + this->vscroll_bo = this->GetScrollbar(RPLALL_GUI_SCROLL_BO); + this->vscroll_tl->SetStepSize(16); + this->vscroll_tr->SetStepSize(16); + this->vscroll_bo->SetStepSize(16); + + this->FinishInitNested(VEH_TRAIN); + + this->owner = _local_company; + + engines_left = new GUIEngineList(); + engines_right = new GUIEngineList(); + virtualTrains = new VirtTrainList(); + + this->GenerateBuyableEnginesList(); + this->GenerateIncludedTemplateList(); + + this->line_height = 16; + this->selected_left = -1; + this->selected_right = -1; + } + + ~TemplateReplacementReplaceAllWindow() + { + for ( uint i=0; ivirtualTrains->Length(); ++i ) + delete (*this->virtualTrains)[i]->vt; + SetWindowClassesDirty(WC_TEMPLATEGUI_MAIN); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch ( widget ) { + case RPLALL_GUI_MATRIX_TOPLEFT: + case RPLALL_GUI_MATRIX_TOPRIGHT: + case RPLALL_GUI_MATRIX_BOTTOM: { + resize->height = 16; + size->height = 16; + break; + } + } + } + + virtual void OnPaint() + { + this->GetWidget(RPLALL_GUI_PANEL_BUTTONFLUFF_3)->colour = _company_colours[_local_company]; + + this->DrawWidgets(); + } + + virtual void OnResize() + { + NWidgetCore *nwi_tl = this->GetWidget(RPLALL_GUI_MATRIX_TOPLEFT); + this->vscroll_tl->SetCapacityFromWidget(this, RPLALL_GUI_MATRIX_TOPLEFT); + nwi_tl->widget_data = (this->vscroll_tl->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START); + + NWidgetCore *nwi_tr = this->GetWidget(RPLALL_GUI_MATRIX_TOPRIGHT); + this->vscroll_tr->SetCapacityFromWidget(this, RPLALL_GUI_MATRIX_TOPRIGHT); + nwi_tr->widget_data = (this->vscroll_tr->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START); + + NWidgetCore *nwi_bo = this->GetWidget(RPLALL_GUI_MATRIX_BOTTOM); + this->vscroll_bo->SetCapacityFromWidget(this, RPLALL_GUI_MATRIX_BOTTOM); + nwi_bo->widget_data = (this->vscroll_bo->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case RPLALL_GUI_MATRIX_TOPLEFT: { + this->DrawEngineList(r, true); + break; + } + case RPLALL_GUI_MATRIX_TOPRIGHT: { + this->DrawEngineList(r, false); + break; + } + case RPLALL_GUI_MATRIX_BOTTOM: { + this->DrawVirtualTrains(r); + break; + } + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch(widget) { + case RPLALL_GUI_MATRIX_TOPLEFT: { + uint16 newindex = (uint16)((pt.y - this->nested_array[RPLALL_GUI_MATRIX_TOPLEFT]->pos_y) / this->line_height) + this->vscroll_tl->GetPosition(); + if ( newindex >= this->engines_left->Length() || newindex==this->selected_left ) + this->selected_left = -1; + else + this->selected_left = newindex; + this->SetDirty(); + break; + } + case RPLALL_GUI_MATRIX_TOPRIGHT: { + uint16 newindex = (uint16)((pt.y - this->nested_array[RPLALL_GUI_MATRIX_TOPRIGHT]->pos_y) / this->line_height) + this->vscroll_tr->GetPosition(); + if ( newindex > this->engines_right->Length() || newindex==this->selected_right ) + this->selected_right = -1; + else + this->selected_right = newindex; + this->SetDirty(); + break; + } + case RPLALL_GUI_BUTTON_RPLALL: { + this->ReplaceAll(); + break; + } + case RPLALL_GUI_BUTTON_APPLY: { + // check if we actually did anything so far, if not, applying is forbidden + if ( this->virtualTrains->Length() == 0 ) + return; + // first delete all current templates + this->DeleteAllTemplateTrains(); + // then build a new list from the current virtual trains + for ( uint i=0; ivirtualTrains->Length(); ++i ) { + // the relevant info struct + VirtTrainInfo *vti = (*this->virtualTrains)[i]; + // setup template from contained train + Train *t = vti->vt; + TemplateVehicle *tv = TemplateVehicleFromVirtualTrain(t); + // restore template specific stuff + tv->reuse_depot_vehicles = vti->reuse_depot_vehicles; + tv->keep_remaining_vehicles = vti->keep_remaining_vehicles; + tv->refit_as_template = vti->refit_as_template; + tv->cargo_type = vti->cargo_type; + tv->cargo_subtype = vti->cargo_subtype; + // use the original_index information to repoint the relevant TemplateReplacement if existing + TemplateReplacement *tr = GetTemplateReplacementByTemplateID(vti->original_index); + if ( tr ) + tr->sel_template = tv->index; + } + // then close this window and return to parent + delete this; + break; + } + case RPLALL_GUI_BUTTON_CANCEL: { + delete this; + break; + } + } + } + + bool HasTemplateWithEngine(EngineID eid) const + { + const TemplateVehicle *tv; + FOR_ALL_TEMPLATES(tv) { + if ( tv->Prev() || tv->owner != _local_company ) continue; + for ( const TemplateVehicle *tmp=tv; tmp; tmp=tmp->GetNextUnit() ) { + if ( tmp->engine_type == eid ) + return true; + } + } + return false; + } + + void GenerateVirtualTrains() + { + this->virtualTrains->Clear(); + + TemplateVehicle *tv; + FOR_ALL_TEMPLATES(tv) { + if ( !tv->Prev() && tv->owner==this->owner ) { + // setup template train + Train *newtrain = VirtualTrainFromTemplateVehicle(tv); + VirtTrainInfo *vti = new VirtTrainInfo(newtrain); + // store template specific stuff + vti->original_index = tv->index; + vti->reuse_depot_vehicles = tv->reuse_depot_vehicles; + vti->keep_remaining_vehicles = tv->keep_remaining_vehicles; + vti->refit_as_template = tv->refit_as_template; + vti->cargo_type = tv->cargo_type; + vti->cargo_subtype = tv->cargo_subtype; + // add new info struct + *this->virtualTrains->Append() = vti; + } + } + + this->vscroll_bo->SetCount(this->virtualTrains->Length()); + } + + void DeleteAllTemplateTrains() + { + TemplateVehicle *tv, *tmp; + FOR_ALL_TEMPLATES(tv) { + tmp = tv; + if ( tmp->Prev()==0 && tmp->owner==this->owner ) + delete tmp; + } + } + + void GenerateIncludedTemplateList() + { + int num_engines = 0; + int num_wagons = 0; + + this->engines_left->Clear(); + + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { + EngineID eid = e->index; + const RailVehicleInfo*rvi = &e->u.rail; + + if ( !HasTemplateWithEngine(eid) ) continue; + + *this->engines_left->Append() = eid; + + if (rvi->railveh_type != RAILVEH_WAGON) { + num_engines++; + } else { + num_wagons++; + } + } + this->vscroll_tl->SetCount(this->engines_left->Length()); + } + + bool VirtualTrainHasEngineID(EngineID eid) + { + + for ( uint i=0; ivirtualTrains->Length(); ++i ) { + const Train *tmp = (*this->virtualTrains)[i]->vt; + for ( ; tmp; tmp=tmp->Next() ) + if ( tmp->engine_type == eid ) + return true; + } + return false; + } + + // after 'replace all' we need to replace the currently used templates as well + void RebuildIncludedTemplateList() { + // first remove all engine ids + for ( uint i=0; iengines_left->Length(); ++i ) { + EngineID entry = (*this->engines_left)[i]; + if ( !VirtualTrainHasEngineID(entry) ) + this->engines_left->Erase(&((*this->engines_left)[i])); + } + } + + void ReplaceAll() + { + + if ( this->selected_left==-1 || this->selected_right==-1 ) + return; + + EngineID eid_orig = (*this->engines_left)[this->selected_left]; + EngineID eid_repl = (*this->engines_right)[this->selected_right]; + + if ( eid_orig == eid_repl ) + return; + + if ( this->virtualTrains->Length() == 0 ) + this->GenerateVirtualTrains(); + + for ( uint i=0; ivirtualTrains->Length(); ++i ) { + Train *tmp = (*this->virtualTrains)[i]->vt; + while ( tmp ) { + if ( tmp->engine_type == eid_orig ) { + // build a new virtual rail vehicle and test for success + Train *nt = CmdBuildVirtualRailVehicle(eid_repl); + if ( !nt ) continue; + // include the (probably) new engine into the 'included'-list + this->engines_left->Include( nt->engine_type ); + // advance the tmp pointer in the chain, otherwise it would get deleted later on + Train *to_del = tmp; + tmp = tmp->GetNextUnit(); + // first move the new virtual rail vehicle behind to_del + CommandCost move = CmdMoveRailVehicle(INVALID_TILE, DC_EXEC, nt->index|(1<<21), to_del->index, 0); + // then move to_del away from the chain and delete it + move = CmdMoveRailVehicle(INVALID_TILE, DC_EXEC, to_del->index|(1<<21), INVALID_VEHICLE, 0); + (*this->virtualTrains)[i]->vt = nt->First(); + delete to_del; + } else { + tmp = tmp->GetNextUnit(); + } + } + } + this->selected_left = -1; + // rebuild the left engines list as some engines might not be there anymore + this->RebuildIncludedTemplateList(); + this->SetDirty(); + } + + void GenerateBuyableEnginesList() + { + int num_engines = 0; + int num_wagons = 0; + + this->engines_right->Clear(); + + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { + EngineID eid = e->index; + const RailVehicleInfo *rvi = &e->u.rail; + + if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue; + + *this->engines_right->Append() = eid; + + if (rvi->railveh_type != RAILVEH_WAGON) { + num_engines++; + } else { + num_wagons++; + } + } + + /* make engines first, and then wagons, sorted by ListPositionOfEngine() */ + EngList_Sort(this->engines_right, TrainEnginesThenWagonsSorter); + + this->vscroll_tr->SetCount(this->engines_right->Length()); + } + + void DrawEngineList(const Rect &r, bool left) const//, GUIEngineList el, Scrollbar* sb) const + { + uint16 y = r.top; + uint32 eid; + + Scrollbar *sb; + const GUIEngineList *el; + + if ( left ) { + sb = this->vscroll_tl; + el = this->engines_left; + } else { + sb = this->vscroll_tr; + el = this->engines_right; + } + + int maximum = min((int)sb->GetCapacity(), (int)el->Length()) + sb->GetPosition(); + + for ( int i=sb->GetPosition(); iselected_left == i) || (!left && this->selected_right == i) ) + GfxFillRect(r.left, y, r.right, y+this->line_height, _colour_gradient[COLOUR_GREY][3]); + + /* Draw a description string of the current engine */ + SetDParam(0, eid); + DrawString(r.left+100, r.right, y+4, STR_ENGINE_NAME, TC_BLACK); + + /* Draw the engine */ + DrawVehicleEngine( r.left, r.right, r.left+29, y+8, eid, GetEnginePalette(eid, _local_company), EIT_PURCHASE ); + + y += this->line_height; + } + } + + void DrawVirtualTrains(const Rect &r) const + { + uint16 y = r.top; + + uint16 max = min(virtualTrains->Length(), this->vscroll_bo->GetCapacity()); + + for ( uint16 i=vscroll_bo->GetPosition(); iGetPosition(); ++i ) { + /* Draw a virtual train*/ + DrawTrainImage( (*this->virtualTrains)[i]->vt, r.left+32, r.right, y, INVALID_VEHICLE, EIT_PURCHASE, 0, -1 ); + + y+= this->line_height; + } + } +}; + +void ShowTemplateReplaceAllGui() +{ + new TemplateReplacementReplaceAllWindow(&_template_replace_replaceall_desc); +} diff --git a/src/tbtr_template_gui_replaceall.h b/src/tbtr_template_gui_replaceall.h new file mode 100644 index 0000000000..10b9ccd3bc --- /dev/null +++ b/src/tbtr_template_gui_replaceall.h @@ -0,0 +1,27 @@ +#ifndef TMPL_RPLALL_GUI +#define TMPL_RPLALL_GUI + + + +#include "stdafx.h" +#include "window_gui.h" +#include "window_func.h" + +#include "company_func.h" +#include "engine_base.h" +#include "engine_func.h" +#include "engine_gui.h" +#include "train.h" +#include "strings_func.h" +#include "vehicle_base.h" +#include "vehicle_func.h" + +#include "tbtr_template_vehicle.h" +#include "tbtr_template_vehicle_func.h" + +#include "core/math_func.hpp" +#include "table/strings.h" + +void ShowTemplateReplaceAllGui(); + +#endif \ No newline at end of file diff --git a/src/tbtr_template_vehicle.cpp b/src/tbtr_template_vehicle.cpp new file mode 100644 index 0000000000..23036e64ba --- /dev/null +++ b/src/tbtr_template_vehicle.cpp @@ -0,0 +1,227 @@ +#include "stdafx.h" +#include "company_func.h" +#include "train.h" +#include "command_func.h" +#include "engine_func.h" +#include "vehicle_func.h" +#include "autoreplace_func.h" +#include "autoreplace_gui.h" +#include "group.h" +#include "articulated_vehicles.h" +#include "core/random_func.hpp" +#include "core/pool_type.hpp" +#include "engine_type.h" +#include "group_type.h" +#include "core/pool_func.hpp" + +#include "table/strings.h" + +#include "newgrf.h" + +#include "vehicle_type.h" +#include "vehicle_base.h" +#include "vehicle_func.h" + +#include "table/train_cmd.h" + + +#include "tbtr_template_vehicle.h" + +// since doing stuff with sprites +#include "newgrf_spritegroup.h" +#include "newgrf_engine.h" +#include "newgrf_cargo.h" + +TemplatePool _template_pool("TemplatePool"); +INSTANTIATE_POOL_METHODS(Template) + +TemplateReplacementPool _template_replacement_pool("TemplateReplacementPool"); +INSTANTIATE_POOL_METHODS(TemplateReplacement) + + +TemplateVehicle::TemplateVehicle(VehicleType ty, EngineID eid, byte subtypeflag, Owner current_owner) +{ + this->type = ty; + this->engine_type = eid; + + this->reuse_depot_vehicles = true; + this->keep_remaining_vehicles = true; + + this->first = this; + this->next = 0x0; + this->previous = 0x0; + this->owner_b = _current_company; + + this->cur_image = SPR_IMG_QUERY; + + this->owner = current_owner; + + this->real_consist_length = 0; +} + +TemplateVehicle::~TemplateVehicle() { + TemplateVehicle *v = this->Next(); + this->SetNext(NULL); + + delete v; +} + +/** getting */ +void TemplateVehicle::SetNext(TemplateVehicle *v) { this->next = v; } +void TemplateVehicle::SetPrev(TemplateVehicle *v) { this->previous = v; } +void TemplateVehicle::SetFirst(TemplateVehicle *v) { this->first = v; } + +TemplateVehicle* TemplateVehicle::GetNextUnit() const +{ + TemplateVehicle *tv = this->Next(); + while ( tv && HasBit(tv->subtype, GVSF_ARTICULATED_PART) ) tv = tv->Next(); + if ( tv && HasBit(tv->subtype, GVSF_MULTIHEADED) && !HasBit(tv->subtype, GVSF_ENGINE) ) tv = tv->Next(); + return tv; +} + +TemplateVehicle* TemplateVehicle::GetPrevUnit() +{ + TemplateVehicle *tv = this->Prev(); + while ( tv && HasBit(tv->subtype, GVSF_ARTICULATED_PART|GVSF_ENGINE) ) tv = tv->Prev(); + if ( tv && HasBit(tv->subtype, GVSF_MULTIHEADED|GVSF_ENGINE) ) tv = tv->Prev(); + return tv; +} + +/** setting */ +void appendTemplateVehicle(TemplateVehicle *orig, TemplateVehicle *newv) +{ + if ( !orig ) return; + while ( orig->Next() ) orig=orig->Next(); + orig->SetNext(newv); + newv->SetPrev(orig); + newv->SetFirst(orig->First()); +} + +void insertTemplateVehicle(TemplateVehicle *orig, TemplateVehicle *newv, TemplateVehicle *insert_after) +{ + if ( !orig || !insert_after ) return; + TemplateVehicle *insert_before = insert_after->Next(); + insert_after->SetNext(newv); + insert_before->SetPrev(newv); + newv->SetPrev(insert_after); + newv->SetNext(insert_before); + newv->SetFirst(insert_after); +} + +/** Length() + * @return: length of vehicle, including current part + */ +int TemplateVehicle::Length() const +{ + int l=1; + const TemplateVehicle *tmp=this; + while ( tmp->Next() ) { tmp=tmp->Next(); l++; } + return l; +} + +TemplateReplacement* GetTemplateReplacementByGroupID(GroupID gid) +{ + TemplateReplacement *tr; + FOR_ALL_TEMPLATE_REPLACEMENTS(tr) { + if ( tr->Group() == gid ) + return tr; + } + return 0; +} + +TemplateReplacement* GetTemplateReplacementByTemplateID(TemplateID tid) { + TemplateReplacement *tr; + FOR_ALL_TEMPLATE_REPLACEMENTS(tr) { + if ( tr->Template() == tid ) + return tr; + } + return 0; +} + +bool IssueTemplateReplacement(GroupID gid, TemplateID tid) { + + TemplateReplacement *tr = GetTemplateReplacementByGroupID(gid); + + if ( tr ) { + /* Then set the new TemplateVehicle and return */ + tr->SetTemplate(tid); + return true; + } + + else if ( TemplateReplacement::CanAllocateItem() ) { + tr = new TemplateReplacement(gid, tid); + return true; + } + + else return false; +} + +short TemplateVehicle::NumGroupsUsingTemplate() const +{ + short amount = 0; + const TemplateReplacement *tr; + FOR_ALL_TEMPLATE_REPLACEMENTS(tr) { + if ( tr->sel_template == this->index ) + amount++; + } + return amount; +} + +short TemplateVehicle::CountEnginesInChain() +{ + TemplateVehicle *tv = this->first; + short count = 0; + for ( ; tv; tv=tv->GetNextUnit() ) + if ( HasBit(tv->subtype, GVSF_ENGINE ) ) + count++; + return count; +} + +short deleteIllegalTemplateReplacements(GroupID g_id) +{ + short del_amount = 0; + const TemplateReplacement *tr; + FOR_ALL_TEMPLATE_REPLACEMENTS(tr) { + if ( tr->group == g_id ) { + delete tr; + del_amount++; + } + } + return del_amount; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/tbtr_template_vehicle.h b/src/tbtr_template_vehicle.h new file mode 100644 index 0000000000..82aeecfcda --- /dev/null +++ b/src/tbtr_template_vehicle.h @@ -0,0 +1,195 @@ +#ifndef TEMPLATE_VEH_H +#define TEMPLATE_VEH_H + +#include "company_func.h" + +#include "vehicle_type.h" +#include "vehicle_base.h" +#include "vehicle_func.h" + +#include "articulated_vehicles.h" +#include "newgrf_callbacks.h" +#include "newgrf_engine.h" +#include "newgrf_spritegroup.h" + +#include "engine_base.h" +#include "engine_type.h" +#include "engine_func.h" + +#include "sortlist_type.h" + +#define FOR_ALL_TEMPLATES_FROM(var, start) FOR_ALL_ITEMS_FROM(TemplateVehicle, template_index, var, start) +#define FOR_ALL_TEMPLATES(var) FOR_ALL_TEMPLATES_FROM(var, 0) + +#define FOR_ALL_TEMPLATE_REPLACEMENTS_FROM(var, start) FOR_ALL_ITEMS_FROM(TemplateReplacement, template_replacement_index, var, start) +#define FOR_ALL_TEMPLATE_REPLACEMENTS(var) FOR_ALL_TEMPLATE_REPLACEMENTS_FROM(var, 0) + +struct TemplateVehicle; +struct TemplateReplacement; + +CommandCost CmdBuildTemplateVehicle(uint i, DoCommandFlag flags, uint p1, uint p2, char const* text); +CommandCost CmdTemplateReplaceVehicle(uint i, DoCommandFlag flags, uint p1, uint p2, char const* text); +typedef uint16 TemplateID; + + +static const uint16 CONSIST_HEAD = 0x0; +static const uint16 CONSIST_TAIL = 0xffff; + +/** A pool allowing to store up to ~64k templates */ +typedef Pool TemplatePool; +extern TemplatePool _template_pool; + +/// listing/sorting templates +typedef GUIList GUITemplateList; + +struct TemplateVehicle : TemplatePool::PoolItem<&_template_pool>, BaseVehicle { +private: + TemplateVehicle *next; ///< pointer to the next vehicle in the chain + TemplateVehicle *previous; ///< NOSAVE: pointer to the previous vehicle in the chain + TemplateVehicle *first; ///< NOSAVE: pointer to the first vehicle in the chain + +public: + friend const SaveLoad* GTD(); + friend void AfterLoadTemplateVehicles(); + + // Template usage configuration + bool reuse_depot_vehicles; + bool keep_remaining_vehicles; + bool refit_as_template; + + // Things derived from a virtual train + TemplateVehicle *other_multiheaded_part; ///< Multiheaded Engine support + Money value; ///< Value of the vehicle + Owner owner; + OwnerByte owner_b; + + EngineID engine_type; ///< The type of engine used for this vehicle. + CargoID cargo_type; ///< type of cargo this vehicle is carrying + uint16 cargo_cap; ///< total capacity + byte cargo_subtype; + + byte subtype; + RailTypeByte railtype; + + VehicleID index; + + uint16 real_consist_length; + + uint16 max_speed; + uint32 power; + uint32 weight; + uint32 max_te; + + byte spritenum; + SpriteID cur_image; + uint32 image_width; + const SpriteGroup *sgroup; + + TemplateVehicle(VehicleType type=VEH_INVALID, EngineID e=INVALID_ENGINE, byte B=0, Owner=_local_company); + TemplateVehicle(EngineID, RailVehicleInfo*); + TemplateVehicle(EngineID eid) { + next=0; + previous=0; + first=this; + engine_type=eid; + this->reuse_depot_vehicles = true; + this->keep_remaining_vehicles = true; + this->refit_as_template = true; + } + ~TemplateVehicle(); + + inline TemplateVehicle* Next() const { return this->next; } + inline TemplateVehicle* Prev() const { return this->previous; } + inline TemplateVehicle* First() const { return this->first; } + + void SetNext(TemplateVehicle*); + void SetPrev(TemplateVehicle*); + void SetFirst(TemplateVehicle*); + + TemplateVehicle* GetNextUnit() const; + TemplateVehicle* GetPrevUnit(); + + bool IsSetReuseDepotVehicles() const { return this->reuse_depot_vehicles; } + bool IsSetKeepRemainingVehicles() const { return this->keep_remaining_vehicles; } + bool IsSetRefitAsTemplate() const { return this->refit_as_template; } + void ToggleReuseDepotVehicles() { this->reuse_depot_vehicles = !this->reuse_depot_vehicles; } + void ToggleKeepRemainingVehicles() { this->keep_remaining_vehicles = !this->keep_remaining_vehicles; } + void ToggleRefitAsTemplate() { this->refit_as_template = !this->refit_as_template; } + + bool IsPrimaryVehicle() const { return this->IsFrontEngine(); } + inline bool IsFrontEngine() const { return HasBit(this->subtype, GVSF_FRONT); } + inline bool HasArticulatedPart() const { return this->Next() != NULL && this->Next()->IsArticulatedPart(); } + + inline bool IsArticulatedPart() const { return HasBit(this->subtype, GVSF_ARTICULATED_PART); } + inline bool IsMultiheaded() const { return HasBit(this->subtype, GVSF_MULTIHEADED); } + + inline bool IsFreeWagonChain() const { return HasBit(this->subtype, GVSF_FREE_WAGON); } + + // since CmdBuildTemplateVehicle(...) + inline void SetFrontEngine() { SetBit(this->subtype, GVSF_FRONT); } + inline void SetEngine() { SetBit(this->subtype, GVSF_ENGINE); } + inline void SetArticulatedPart() { SetBit(this->subtype, GVSF_ARTICULATED_PART); } + inline void SetMultiheaded() { SetBit(this->subtype, GVSF_MULTIHEADED); } + + inline void SetWagon() { SetBit(this->subtype, GVSF_WAGON); } + inline void SetFreeWagon() { SetBit(this->subtype, GVSF_FREE_WAGON); } + + inline uint16 GetRealLength() const { return this->real_consist_length; } + inline void SetRealLength(uint16 len) { this->real_consist_length = len; } + + int Length() const; + + SpriteID GetImage(Direction) const; + //int GetDisplayImageWidth(Point *offset = NULL) const; + SpriteID GetSpriteID() const; + + short NumGroupsUsingTemplate() const; + + short CountEnginesInChain(); + +}; + +void appendTemplateVehicle(TemplateVehicle*, TemplateVehicle*); +void insertTemplateVehicle(TemplateVehicle*, TemplateVehicle*, TemplateVehicle*); + +void NeutralizeVehicleStatus(Train*); +void SplitVehicleRemainders(Train*); + +// TemplateReplacement stuff + +typedef Pool TemplateReplacementPool; +extern TemplateReplacementPool _template_replacement_pool; + +struct TemplateReplacement : TemplateReplacementPool::PoolItem<&_template_replacement_pool> { + GroupID group; + TemplateID sel_template; + + TemplateReplacement(GroupID gid, TemplateID tid) { this->group=gid; this->sel_template=tid; } + TemplateReplacement() {} + ~TemplateReplacement() {} + + inline GroupID Group() { return this->group; } + inline GroupID Template() { return this->sel_template; } + + inline void SetGroup(GroupID gid) { this->group = gid; } + inline void SetTemplate(TemplateID tid) { this->sel_template = tid; } + + inline TemplateID GetTemplateVehicleID() { return sel_template; } + inline const TemplateVehicle* GetTemplateVehicle() { + const TemplateVehicle *tv; + FOR_ALL_TEMPLATES(tv) { + if ( tv->index == this->sel_template ) + return tv; + } + return NULL; + } +}; + +TemplateReplacement* GetTemplateReplacementByGroupID(GroupID); +TemplateReplacement* GetTemplateReplacementByTemplateID(TemplateID); +bool IssueTemplateReplacement(GroupID, TemplateID); + +short deleteIllegalTemplateReplacements(GroupID); + +#endif /* TEMPLATE_VEH_H */ + diff --git a/src/tbtr_template_vehicle_func.cpp b/src/tbtr_template_vehicle_func.cpp new file mode 100644 index 0000000000..69f847a674 --- /dev/null +++ b/src/tbtr_template_vehicle_func.cpp @@ -0,0 +1,773 @@ +// template_vehicle_func.cpp + +#include "stdafx.h" +#include "window_gui.h" +#include "gfx_func.h" +#include "window_func.h" +#include "command_func.h" +#include "vehicle_gui.h" +#include "train.h" +#include "strings_func.h" +#include "vehicle_func.h" +#include "core/geometry_type.hpp" +#include "debug.h" + +#include "table/sprites.h" +#include "table/strings.h" + +#include "cargoaction.h" +#include "train.h" +#include "company_func.h" +#include "newgrf.h" +#include "spritecache.h" +#include "articulated_vehicles.h" +#include "autoreplace_func.h" + +#include "depot_base.h" + +#include "tbtr_template_vehicle.h" +#include "tbtr_template_vehicle_func.h" + +#include +#include + +Vehicle *vhead, *vtmp; +static const uint MAX_ARTICULATED_PARTS = 100; + + +// debugging printing functions for convenience, usually called from gdb +void pat() { + TemplateVehicle *tv; + FOR_ALL_TEMPLATES(tv) { + if ( tv->Prev() ) continue; + ptv(tv); + printf("__________\n"); + } +} +void pav() { + Train *t; + FOR_ALL_TRAINS(t) { + if ( t->Previous() ) continue; + pvt(t); + printf("__________\n"); + } +} +void ptv(TemplateVehicle* tv) { + if (!tv) return; + while (tv->Next() ) { + printf("eid:%3d st:%2d tv:%x next:%x cargo: %d cargo_sub: %d\n", tv->engine_type, tv->subtype, tv, tv->Next(), tv->cargo_type, tv->cargo_subtype); + tv = tv->Next(); + } + printf("eid:%3d st:%2d tv:%x next:%x cargo: %d cargo_sub: %d\n", tv->engine_type, tv->subtype, tv, tv->Next(), tv->cargo_type, tv->cargo_subtype); +} + +void pvt (const Train *printme) { + for ( const Train *tmp = printme; tmp; tmp=tmp->Next() ) { + if ( tmp->index <= 0 ) { + printf("train has weird index: %d %d %x\n", tmp->index, tmp->engine_type, (__int64)tmp); + return; + } + printf("eid:%3d index:%2d subtype:%2d vehstat: %d cargo_t: %d cargo_sub: %d ref:%x\n", tmp->engine_type, tmp->index, tmp->subtype, tmp->vehstatus, tmp->cargo_type, tmp->cargo_subtype, tmp); + } +} + +void BuildTemplateGuiList(GUITemplateList *list, Scrollbar *vscroll, Owner oid, RailType railtype) +{ + list->Clear(); + const TemplateVehicle *tv; + + FOR_ALL_TEMPLATES(tv) { + if (tv->owner == oid && (tv->IsPrimaryVehicle() || tv->IsFreeWagonChain()) && TemplateVehicleContainsEngineOfRailtype(tv, railtype)) + *list->Append() = tv; + + } + + list->RebuildDone(); + if (vscroll) vscroll->SetCount(list->Length()); +} + +Money CalculateOverallTemplateCost(const TemplateVehicle *tv) +{ + Money val = 0; + + for (; tv; tv = tv->Next()) + val += (Engine::Get(tv->engine_type))->GetCost(); + return val; +} + +void DrawTemplate(const TemplateVehicle *tv, int left, int right, int y) +{ + if ( !tv ) return; + + const TemplateVehicle *t = tv; + int offset=left; + + while (t) { + PaletteID pal = GetEnginePalette(t->engine_type, _current_company); + DrawSprite(t->cur_image, pal, offset, y+12); + + offset += t->image_width; + t = t->Next(); + } +} + +// copy important stuff from the virtual vehicle to the template +inline void SetupTemplateVehicleFromVirtual(TemplateVehicle *tmp, TemplateVehicle *prev, Train *virt) +{ + if (prev) { + prev->SetNext(tmp); + tmp->SetPrev(prev); + tmp->SetFirst(prev->First()); + } + tmp->railtype = virt->railtype; + tmp->owner = virt->owner; + tmp->value = virt->value; + + // set the subtype but also clear the virtual flag while doing it + tmp->subtype = virt->subtype & ~(1 << GVSF_VIRTUAL); + // set the cargo type and capacity + tmp->cargo_type = virt->cargo_type; + tmp->cargo_subtype = virt->cargo_subtype; + tmp->cargo_cap = virt->cargo_cap; + + const GroundVehicleCache *gcache = virt->GetGroundVehicleCache(); + tmp->max_speed = virt->GetDisplayMaxSpeed(); + tmp->power = gcache->cached_power; + tmp->weight = gcache->cached_weight; + tmp->max_te = gcache->cached_max_te / 1000; + + tmp->spritenum = virt->spritenum; + tmp->cur_image = virt->GetImage(DIR_W, EIT_PURCHASE); + Point *p = new Point(); + tmp->image_width = virt->GetDisplayImageWidth(p); +} + +// create a new virtual train as clone of a real train +Train* CloneVirtualTrainFromTrain(const Train *clicked) +{ + if ( !clicked ) return 0; + CommandCost c; + Train *tmp, *head, *tail; + + head = CmdBuildVirtualRailVehicle(clicked->engine_type); + if ( !head ) return 0; + + tail = head; + clicked = clicked->GetNextUnit(); + while ( clicked ) { + tmp = CmdBuildVirtualRailVehicle(clicked->engine_type); + if ( tmp ) { + tmp->cargo_type = clicked->cargo_type; + tmp->cargo_subtype = clicked->cargo_subtype; + CmdMoveRailVehicle(0, DC_EXEC, (1<<21) | tmp->index, tail->index, 0); + tail = tmp; + } + clicked = clicked->GetNextUnit(); + } + return head; +} +TemplateVehicle* CloneTemplateVehicleFromTrain(const Train *t) +{ + Train *clicked = Train::Get(t->index); + if ( !clicked ) + return 0; + + Train *init_clicked = clicked; + + int len = CountVehiclesInChain(clicked); + if ( !TemplateVehicle::CanAllocateItem(len) ) + return 0; + + TemplateVehicle *tmp, *prev=0; + for ( ; clicked; clicked=clicked->Next() ) { + tmp = new TemplateVehicle(clicked->engine_type); + SetupTemplateVehicleFromVirtual(tmp, prev, clicked); + prev = tmp; + } + + tmp->First()->SetRealLength(CeilDiv(init_clicked->gcache.cached_total_length * 10, TILE_SIZE)); + return tmp->First(); +} +// create a full TemplateVehicle based train according to a virtual train +TemplateVehicle* TemplateVehicleFromVirtualTrain(Train *virt) +{ + if ( !virt ) + return 0; + + Train *init_virt = virt; + + int len = CountVehiclesInChain(virt); + if ( !TemplateVehicle::CanAllocateItem(len) ) + return 0; + + TemplateVehicle *tmp, *prev=0; + for ( ; virt; virt=virt->Next() ) { + tmp = new TemplateVehicle(virt->engine_type); + SetupTemplateVehicleFromVirtual(tmp, prev, virt); + prev = tmp; + } + + tmp->First()->SetRealLength(CeilDiv(init_virt->gcache.cached_total_length * 10, TILE_SIZE)); + return tmp->First(); +} + +// attempt to buy a train after a given template vehicle +// this might fail if the template e.g. deprecated and contains engines that are not sold anymore +Train* VirtualTrainFromTemplateVehicle(TemplateVehicle *tv) +{ + if ( !tv ) return 0; + CommandCost c; + Train *tmp, *head, *tail; + + head = CmdBuildVirtualRailVehicle(tv->engine_type); + if ( !head ) return 0; + + tail = head; + tv = tv->GetNextUnit(); + while ( tv ) { + tmp = CmdBuildVirtualRailVehicle(tv->engine_type); + if ( tmp ) { + tmp->cargo_type = tv->cargo_type; + tmp->cargo_subtype = tv->cargo_subtype; + CmdMoveRailVehicle(INVALID_TILE, DC_EXEC, (1<<21) | tmp->index, tail->index, 0); + tail = tmp; + } + tv = tv->GetNextUnit(); + } + return head; +} + +// return last in a chain (really last, so even a singular articulated part of a vehicle if the last one is artic) +inline TemplateVehicle* Last(TemplateVehicle *chain) { + if ( !chain ) return 0; + while ( chain->Next() ) chain = chain->Next(); + return chain; +} + +inline Train* Last(Train *chain) { + if ( !chain ) return 0; + while ( chain->GetNextUnit() ) chain = chain->GetNextUnit(); + return chain; +} + +// return: pointer to former vehicle +TemplateVehicle *DeleteTemplateVehicle(TemplateVehicle *todel) +{ + if ( !todel ) + return 0; + TemplateVehicle *cur = todel; + delete todel; + return cur; +} + +// forward declaration, defined in train_cmd.cpp +CommandCost CmdSellRailWagon(DoCommandFlag, Vehicle*, uint16, uint32); + +Train* DeleteVirtualTrain(Train *chain, Train *to_del) { + if ( chain != to_del ) { + CmdSellRailWagon(DC_EXEC, to_del, 0, 0); + return chain; + } + else { + chain = chain->GetNextUnit(); + CmdSellRailWagon(DC_EXEC, to_del, 0, 0); + return chain; + } +} + +// retrieve template vehicle from templatereplacement that belongs to the given group +TemplateVehicle* GetTemplateVehicleByGroupID(GroupID gid) { + TemplateReplacement *tr; + // first try to find a templatereplacement issued for the given groupid + FOR_ALL_TEMPLATE_REPLACEMENTS(tr) { + if ( tr->Group() == gid ) + return TemplateVehicle::GetIfValid(tr->Template()); // there can be only one + } + // if that didn't work, try to find a templatereplacement for ALL_GROUP + if ( gid != ALL_GROUP ) + FOR_ALL_TEMPLATE_REPLACEMENTS(tr) { + if ( tr->Group() == ALL_GROUP ) + return TemplateVehicle::GetIfValid(tr->Template()); + } + // if all failed, just return null + return 0; +} + +/** + * Check a template consist whether it contains any engine of the given railtype + */ +bool TemplateVehicleContainsEngineOfRailtype(const TemplateVehicle *tv, RailType type) +{ + /* For standard rail engines, allow only those */ + if ( type == RAILTYPE_BEGIN || type == RAILTYPE_RAIL ) { + while ( tv ) { + if ( tv->railtype != type ) + return false; + tv = tv->GetNextUnit(); + } + return true; + } + /* For electrified rail engines, standard wagons or engines are allowed to be included */ + while ( tv ) { + if ( tv->railtype == type ) + return true; + tv = tv->GetNextUnit(); + } + return false; +} + +//helper +bool ChainContainsVehicle(Train *chain, Train *mem) { + for (; chain; chain=chain->Next()) + if ( chain == mem ) + return true; + return false; +} + +// has O(n) +Train* ChainContainsEngine(EngineID eid, Train *chain) { + for (; chain; chain=chain->GetNextUnit()) + if (chain->engine_type == eid) + return chain; + return 0; +} + +// has O(n^2) +Train* DepotContainsEngine(TileIndex tile, EngineID eid, Train *not_in=0) { + Train *t; + FOR_ALL_TRAINS(t) { + // conditions: v is stopped in the given depot, has the right engine and if 'not_in' is given v must not be contained within 'not_in' + // if 'not_in' is NULL, no check is needed + if ( t->tile==tile + // If the veh belongs to a chain, wagons will not return true on IsStoppedInDepot(), only primary vehicles will + // in case of t not a primary veh, we demand it to be a free wagon to consider it for replacement + && ((t->IsPrimaryVehicle() && t->IsStoppedInDepot()) || t->IsFreeWagon()) + && t->engine_type==eid + && (not_in==0 || ChainContainsVehicle(not_in, t)==0)) + return t; + } + return 0; +} + +void CopyStatus(Train *from, Train *to) { + DoCommand(to->tile, from->group_id, to->index, DC_EXEC, CMD_ADD_VEHICLE_GROUP); + to->cargo_type = from->cargo_type; + to->cargo_subtype = from->cargo_subtype; + + // swap names + char *tmp = to->name; + to->name = from->name; + from->name = tmp; + /*if ( !from->name || !to->name ) { + int tmpind = from->index; + from->index = to->index; + to->index = tmpind; + }*/ +} +void NeutralizeStatus(Train *t) { + DoCommand(t->tile, DEFAULT_GROUP, t->index, DC_EXEC, CMD_ADD_VEHICLE_GROUP); + + t->name = 0; +} +bool TrainMatchesTemplate(const Train *t, TemplateVehicle *tv) { + while ( t && tv ) { + if ( t->engine_type != tv->engine_type ) + return false; + t = t->GetNextUnit(); + tv = tv->GetNextUnit(); + } + if ( (t && !tv) || (!t && tv) ) + return false; + return true; +} + + +bool TrainMatchesTemplateRefit(const Train *t, TemplateVehicle *tv) +{ + if ( !tv->refit_as_template ) + return true; + + while ( t && tv ) { + if ( t->cargo_type != tv->cargo_type || t->cargo_subtype != tv->cargo_subtype ) + return false; + t = t->GetNextUnit(); + tv = tv->GetNextUnit(); + } + return true; +} +void BreakUpRemainders(Train *t) { + while ( t ) { + Train *move; + if ( HasBit(t->subtype, GVSF_ENGINE) ) { + move = t; + t = t->Next(); + DoCommand(move->tile, move->index, INVALID_VEHICLE, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); + NeutralizeStatus( move ); + } + else + t = t->Next(); + } +} + +short CountEnginesInChain(Train *t) +{ + short count = 0; + for ( ; t; t=t->GetNextUnit() ) + if ( HasBit(t->subtype, GVSF_ENGINE) ) + count++; + return count; +} + +int countOccurrencesInTrain(Train *t, EngineID eid) { + int count = 0; + Train *tmp = t; + for ( ; tmp; tmp=tmp->GetNextUnit() ) + if ( tmp->engine_type == eid ) + count++; + return count; +} + +int countOccurrencesInTemplateVehicle(TemplateVehicle *contain, EngineID eid) { + int count = 0; + for ( ; contain; contain=contain->GetNextUnit() ) + if ( contain->engine_type == eid ) + count++; + return count; +} + +int countOccurrencesInDepot(TileIndex tile, EngineID eid, Train *not_in=0) { + int count = 0; + Vehicle *v; + FOR_ALL_VEHICLES(v) { + // conditions: v is stopped in the given depot, has the right engine and if 'not_in' is given v must not be contained within 'not_in' + // if 'not_in' is NULL, no check is needed + if ( v->tile==tile && v->IsStoppedInDepot() && v->engine_type==eid && + (not_in==0 || ChainContainsVehicle(not_in, (Train*)v)==0)) + count++; + } + return count; +} + +// basically does the same steps as CmdTemplateReplaceVehicle but without actually moving things around +CommandCost CalculateTemplateReplacementCost(Train *incoming) { + TileIndex tile = incoming->tile; + TemplateVehicle *tv = GetTemplateVehicleByGroupID(incoming->group_id); + CommandCost estimate(EXPENSES_NEW_VEHICLES); + + // count for each different eid in the incoming train + std::map unique_eids; + for ( TemplateVehicle *tmp=tv; tmp; tmp=tmp->GetNextUnit() ) + unique_eids[tmp->engine_type]++; + std::map::iterator it = unique_eids.begin(); + for ( ; it!=unique_eids.end(); it++ ) { + it->second -= countOccurrencesInTrain(incoming, it->first); + it->second -= countOccurrencesInDepot(incoming->tile, it->first, incoming); + if ( it->second < 0 ) it->second = 0; + } + + // get overall buying cost + for ( it=unique_eids.begin(); it!=unique_eids.end(); it++ ) { + for ( int j=0; jsecond; j++ ) { + estimate.AddCost(DoCommand(tile, it->first, 0, DC_NONE, CMD_BUILD_VEHICLE)); + } + } + + return estimate; +} + +// make sure the real train wagon has the right cargo +void CopyWagonStatus(TemplateVehicle *from, Train *to) { + to->cargo_type = from->cargo_type; + to->cargo_subtype = from->cargo_subtype; +} + +int NumTrainsNeedTemplateReplacement(GroupID g_id, TemplateVehicle *tv) +{ + int count = 0; + if ( !tv ) return count; + + const Train *t; + FOR_ALL_TRAINS(t) { + if ( t->IsPrimaryVehicle() && t->group_id == g_id && (!TrainMatchesTemplate(t, tv) || !TrainMatchesTemplateRefit(t, tv)) ) + count++; + } + return count; +} +// refit each vehicle in t as is in tv, assume t and tv contain the same types of vehicles +static void RefitTrainFromTemplate(Train *t, TemplateVehicle *tv) +{ + while ( t && tv ) { + // refit t as tv + uint32 cb = GetCmdRefitVeh(t); + + DoCommandP(t->tile, t->index, tv->cargo_type | tv->cargo_subtype << 8 | 1 << 16 , cb); + + // next + t = t->GetNextUnit(); + tv = tv->GetNextUnit(); + } +} + +/** using cmdtemplatereplacevehicle as test-function (i.e. with flag DC_NONE) is not a good idea as that function relies on + * actually moving vehicles around to work properly. + * We do this worst-cast test instead. + */ +CommandCost TestBuyAllTemplateVehiclesInChain(TemplateVehicle *tv, TileIndex tile) +{ + CommandCost cost(EXPENSES_NEW_VEHICLES); + + for ( ; tv; tv=tv->GetNextUnit() ) + cost.AddCost( DoCommand(tile, tv->engine_type, 0, DC_NONE, CMD_BUILD_VEHICLE) ); + + return cost; +} + + +/** Transfer as much cargo from a given (single train) vehicle onto a chain of vehicles. + * I.e., iterate over the chain from head to tail and use all available cargo capacity (w.r.t. cargo type of course) + * to store the cargo from the given single vehicle. + * @param old_veh: ptr to the single vehicle, which's cargo shall be moved + * @param new_head: ptr to the head of the chain, which shall obtain old_veh's cargo + * @return: amount of moved cargo TODO + */ +void TransferCargoForTrain(Train *old_veh, Train *new_head) +{ + assert(new_head->IsPrimaryVehicle()); + + CargoID _cargo_type = old_veh->cargo_type; + byte _cargo_subtype = old_veh->cargo_subtype; + + // how much cargo has to be moved (if possible) + uint remainingAmount = old_veh->cargo.TotalCount(); + // each vehicle in the new chain shall be given as much of the old cargo as possible, until none is left + for (Train *tmp=new_head; tmp!=NULL && remainingAmount>0; tmp=tmp->GetNextUnit()) + { + if (tmp->cargo_type == _cargo_type && tmp->cargo_subtype == _cargo_subtype) + { + // calculate the free space for new cargo on the current vehicle + uint curCap = tmp->cargo_cap - tmp->cargo.TotalCount(); + uint moveAmount = std::min(remainingAmount, curCap); + // move (parts of) the old vehicle's cargo onto the current vehicle of the new chain + if (moveAmount > 0) + { + old_veh->cargo.Shift(moveAmount, &tmp->cargo); + remainingAmount -= moveAmount; + } + } + } + + // TODO: needs to be implemented, too + // // from autoreplace_cmd.cpp : 121 + /* Any left-overs will be thrown away, but not their feeder share. */ + //if (src->cargo_cap < src->cargo.TotalCount()) src->cargo.Truncate(src->cargo.TotalCount() - src->cargo_cap); + + /* Update train weight etc., the old vehicle will be sold anyway */ + new_head->ConsistChanged(ConsistChangeFlags::CCF_LOADUNLOAD); +} + +// TODO: fit signature to regular cmd-structure +// do something with move_cost, it is not used right now +// if exec==DC_EXEC, test first and execute if sucessful +CommandCost CmdTemplateReplaceVehicle(Train *incoming, bool stayInDepot, DoCommandFlag flags) { + Train *new_chain=0, + *remainder_chain=0, + *tmp_chain=0; + TileIndex tile = incoming->tile; + TemplateVehicle *tv = GetTemplateVehicleByGroupID(incoming->group_id); + EngineID eid = tv->engine_type; + + CommandCost buy(EXPENSES_NEW_VEHICLES); + CommandCost move_cost(EXPENSES_NEW_VEHICLES); + CommandCost tmp_result(EXPENSES_NEW_VEHICLES); + + + /* first some tests on necessity and sanity */ + if ( !tv ) + return buy; + bool need_replacement = !TrainMatchesTemplate(incoming, tv); + bool need_refit = !TrainMatchesTemplateRefit(incoming, tv); + bool use_refit = tv->refit_as_template; + CargoID store_refit_ct = CT_INVALID; + short store_refit_csubt = 0; + // if a train shall keep its old refit, store the refit setting of its first vehicle + if ( !use_refit ) { + for ( Train *getc=incoming; getc; getc=getc->GetNextUnit() ) + if ( getc->cargo_type != CT_INVALID ) { + store_refit_ct = getc->cargo_type; + break; + } + } + + // TODO: set result status to success/no success before returning + if ( !need_replacement ) { + if ( !need_refit || !use_refit ) { + /* before returning, release incoming train first if 2nd param says so */ + if ( !stayInDepot ) incoming->vehstatus &= ~VS_STOPPED; + return buy; + } + } else { + CommandCost buyCost = TestBuyAllTemplateVehiclesInChain(tv, tile); + if ( !buyCost.Succeeded() || !CheckCompanyHasMoney(buyCost) ) { + if ( !stayInDepot ) incoming->vehstatus &= ~VS_STOPPED; + return buy; + } + } + + /* define replacement behaviour */ + bool reuseDepot = tv->IsSetReuseDepotVehicles(); + bool keepRemainders = tv->IsSetKeepRemainingVehicles(); + + if ( need_replacement ) { + /// step 1: generate primary for newchain and generate remainder_chain + // 1. primary of incoming might already fit the template + // leave incoming's primary as is and move the rest to a free chain = remainder_chain + // 2. needed primary might be one of incoming's member vehicles + // 3. primary might be available as orphan vehicle in the depot + // 4. we need to buy a new engine for the primary + // all options other than 1. need to make sure to copy incoming's primary's status + if ( eid == incoming->engine_type ) { // 1 + new_chain = incoming; + remainder_chain = incoming->GetNextUnit(); + if ( remainder_chain ) + move_cost.AddCost(CmdMoveRailVehicle(tile, flags, remainder_chain->index|(1<<20), INVALID_VEHICLE, 0)); + } + else if ( (tmp_chain = ChainContainsEngine(eid, incoming)) && tmp_chain!=NULL ) { // 2 + // new_chain is the needed engine, move it to an empty spot in the depot + new_chain = tmp_chain; + move_cost.AddCost(DoCommand(tile, new_chain->index, INVALID_VEHICLE, flags,CMD_MOVE_RAIL_VEHICLE)); + remainder_chain = incoming; + } + else if ( reuseDepot && (tmp_chain = DepotContainsEngine(tile, eid, incoming)) && tmp_chain!=NULL ) { // 3 + new_chain = tmp_chain; + move_cost.AddCost(DoCommand(tile, new_chain->index, INVALID_VEHICLE, flags, CMD_MOVE_RAIL_VEHICLE)); + remainder_chain = incoming; + } + else { // 4 + tmp_result = DoCommand(tile, eid, 0, flags, CMD_BUILD_VEHICLE); + /* break up in case buying the vehicle didn't succeed */ + if ( !tmp_result.Succeeded() ) + return tmp_result; + buy.AddCost(tmp_result); + new_chain = Train::Get(_new_vehicle_id); + /* make sure the newly built engine is not attached to any free wagons inside the depot */ + move_cost.AddCost ( DoCommand(tile, new_chain->index, INVALID_VEHICLE, flags, CMD_MOVE_RAIL_VEHICLE) ); + /* prepare the remainder chain */ + remainder_chain = incoming; + } + // If we bought a new engine or reused one from the depot, copy some parameters from the incoming primary engine + if ( incoming != new_chain && flags == DC_EXEC) { + CopyHeadSpecificThings(incoming, new_chain, flags); + NeutralizeStatus(incoming); + // additionally, if we don't want to use the template refit, refit as incoming + // the template refit will be set further down, if we use it at all + if ( !use_refit ) { + uint32 cb = GetCmdRefitVeh(new_chain); + DoCommandP(new_chain->tile, new_chain->index, store_refit_ct | store_refit_csubt << 8 | 1 << 16 , cb); + } + + } + + /// step 2: fill up newchain according to the template + // foreach member of template (after primary): + // 1. needed engine might be within remainder_chain already + // 2. needed engine might be orphaned within the depot (copy status) + // 3. we need to buy (again) (copy status) + TemplateVehicle *cur_tmpl = tv->GetNextUnit(); + Train *last_veh = new_chain; + while (cur_tmpl) { + // 1. engine contained in remainder chain + if ( (tmp_chain = ChainContainsEngine(cur_tmpl->engine_type, remainder_chain)) && tmp_chain!=NULL ) { + // advance remainder_chain (if necessary) to not lose track of it + if ( tmp_chain == remainder_chain ) + remainder_chain = remainder_chain->GetNextUnit(); + move_cost.AddCost(CmdMoveRailVehicle(tile, flags, tmp_chain->index, last_veh->index, 0)); + } + // 2. engine contained somewhere else in the depot + else if ( reuseDepot && (tmp_chain = DepotContainsEngine(tile, cur_tmpl->engine_type, new_chain)) && tmp_chain!=NULL ) { + move_cost.AddCost(CmdMoveRailVehicle(tile, flags, tmp_chain->index, last_veh->index, 0)); + } + // 3. must buy new engine + else { + tmp_result = DoCommand(tile, cur_tmpl->engine_type, 0, flags, CMD_BUILD_VEHICLE); + if ( !tmp_result.Succeeded() ) + return tmp_result; + buy.AddCost(tmp_result); + tmp_chain = Train::Get(_new_vehicle_id); + move_cost.AddCost(CmdMoveRailVehicle(tile, flags, tmp_chain->index, last_veh->index, 0)); + } + // TODO: is this enough ? might it be that we bought a new wagon here and it now has std refit ? + if ( need_refit && flags == DC_EXEC ) { + if ( use_refit ) { + uint32 cb = GetCmdRefitVeh(tmp_chain); + DoCommandP(tmp_chain->tile, tmp_chain->index, cur_tmpl->cargo_type | cur_tmpl->cargo_subtype << 8 | 1 << 16 , cb); + // old + // CopyWagonStatus(cur_tmpl, tmp_chain); + } else { + uint32 cb = GetCmdRefitVeh(tmp_chain); + DoCommandP(tmp_chain->tile, tmp_chain->index, store_refit_ct | store_refit_csubt << 8 | 1 << 16 , cb); + } + } + cur_tmpl = cur_tmpl->GetNextUnit(); + last_veh = tmp_chain; + } + } + /* no replacement done */ + else { + new_chain = incoming; + } + /// step 3: reorder and neutralize the remaining vehicles from incoming + // wagons remaining from remainder_chain should be filled up in as few freewagonchains as possible + // each locos might be left as singular in the depot + // neutralize each remaining engine's status + + // refit, only if the template option is set so + if ( use_refit && (need_refit || need_replacement) ) { + RefitTrainFromTemplate(new_chain, tv); + } + + if ( new_chain && remainder_chain ) + for ( Train *ct=remainder_chain; ct; ct=ct->GetNextUnit() ) + TransferCargoForTrain(ct, new_chain); + + // point incoming to the newly created train so that starting/stopping from the calling function can be done + incoming = new_chain; + if ( !stayInDepot && flags == DC_EXEC ) + new_chain->vehstatus &= ~VS_STOPPED; + + if ( remainder_chain && keepRemainders && flags == DC_EXEC ) + BreakUpRemainders(remainder_chain); + else if ( remainder_chain ) { + buy.AddCost(DoCommand(tile, remainder_chain->index | (1<<20), 0, flags, CMD_SELL_VEHICLE)); + } + return buy; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/tbtr_template_vehicle_func.h b/src/tbtr_template_vehicle_func.h new file mode 100644 index 0000000000..b6926f4ba3 --- /dev/null +++ b/src/tbtr_template_vehicle_func.h @@ -0,0 +1,66 @@ +// template_vehicle_func.h +#ifndef TEMPLATE_VEHICLE_FUNC_H +#define TEMPLATE_VEHICLE_FUNC_H + +#include "stdafx.h" +#include "window_gui.h" + +#include "tbtr_template_vehicle.h" + +//void DrawTemplateVehicle(TemplateVehicle*, int, const Rect&); +void DrawTemplateVehicle(const TemplateVehicle*, int, int, int, VehicleID, int, VehicleID); + +void BuildTemplateGuiList(GUITemplateList*, Scrollbar*, Owner, RailType); + +Money CalculateOverallTemplateCost(const TemplateVehicle*); + +void DrawTemplateTrain(const TemplateVehicle*, int, int, int); + +SpriteID GetSpriteID(EngineID, bool); + +void DrawTemplate(const TemplateVehicle*, int, int, int); + +int GetTemplateDisplayImageWidth(EngineID); + +TemplateVehicle *CreateNewTemplateVehicle(EngineID); + +void setupVirtTrain(const TemplateVehicle*, Train*); + +TemplateVehicle* TemplateVehicleFromVirtualTrain(Train*); + +Train* VirtualTrainFromTemplateVehicle(TemplateVehicle*); + +inline TemplateVehicle* Last(TemplateVehicle*); + +TemplateVehicle *DeleteTemplateVehicle(TemplateVehicle*); + +Train* DeleteVirtualTrainPart(Train*, Train*); +Train* DeleteVirtualTrain(Train*, Train *); + +CommandCost CmdTemplateReplaceVehicle(Train*, bool, DoCommandFlag); + +void pat(); +void pav(); +void ptv(TemplateVehicle*); +void pvt(const Train*); +// for testing +TemplateVehicle* GetTemplateVehicleByGroupID(GroupID); +bool ChainContainsVehicle(Train*, Train*); +Train* ChainContainsEngine(EngineID, Train*); +Train* DepotContainsEngine(TileIndex, EngineID, Train*); + +int NumTrainsNeedTemplateReplacement(GroupID, TemplateVehicle*); + +CommandCost TestBuyAllTemplateVehiclesInChain(Train*); +CommandCost CalculateTemplateReplacementCost(Train*); + +short CountEnginesInChain(Train*); + +bool TemplateVehicleContainsEngineOfRailtype(const TemplateVehicle*, RailType); + +Train* CloneVirtualTrainFromTrain(const Train *); +TemplateVehicle* CloneTemplateVehicleFromTrain(const Train *); + +void TransferCargoForTrain(Train*, Train*); + +#endif diff --git a/src/train.h b/src/train.h index 280d59ebdd..70bda2a7cb 100644 --- a/src/train.h +++ b/src/train.h @@ -123,6 +123,7 @@ struct Train FINAL : public GroundVehicle { bool Tick(); void OnNewDay(); uint Crash(bool flooded = false); + Money CalculateCurrentOverallValue() const; Trackdir GetVehicleTrackdir() const; TileIndex GetOrderStationLocation(StationID station); bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse); @@ -163,6 +164,15 @@ struct Train FINAL : public GroundVehicle { return v; } + /* Get the last vehicle of a chain + * @return pointer the last vehicle in a chain + */ + inline Train *GetLastUnit() { + Train *tmp = this; + while ( tmp->GetNextUnit() ) tmp = tmp->GetNextUnit(); + return tmp; + } + /** * Calculate the offset from this vehicle's center to the following center taking the vehicle lengths into account. * @return Offset from center to center. @@ -336,6 +346,13 @@ protected: // These functions should not be called outside acceleration code. } }; + +CommandCost CmdMoveRailVehicle(TileIndex, DoCommandFlag , uint32, uint32, const char *); +CommandCost CmdMoveVirtualRailVehicle(TileIndex, DoCommandFlag, uint32, uint32, const char*); + +Train* CmdBuildVirtualRailWagon(const Engine*); +Train* CmdBuildVirtualRailVehicle(EngineID); + #define FOR_ALL_TRAINS(var) FOR_ALL_VEHICLES_OF_TYPE(Train, var) #endif /* TRAIN_H */ diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 6f2feeaab7..8256de1fcc 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -41,6 +41,8 @@ #include "safeguards.h" +#include "engine_func.h" + static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck); static bool TrainCheckIfLineEnds(Train *v, bool reverse = true); bool TrainController(Train *v, Vehicle *nomove, bool reverse = true); // Also used in vehicle_sl.cpp. @@ -259,7 +261,7 @@ void Train::ConsistChanged(ConsistChangeFlags allowed_changes) if (this->IsFrontEngine()) { this->UpdateAcceleration(); - SetWindowDirty(WC_VEHICLE_DETAILS, this->index); + if ( !HasBit(this->subtype, GVSF_VIRTUAL) ) SetWindowDirty(WC_VEHICLE_DETAILS, this->index); InvalidateWindowData(WC_VEHICLE_REFIT, this->index, VIWD_CONSIST_CHANGED); InvalidateWindowData(WC_VEHICLE_ORDERS, this->index, VIWD_CONSIST_CHANGED); InvalidateNewGRFInspectWindow(GSF_TRAINS, this->index); @@ -1158,6 +1160,7 @@ static void NormaliseTrainHead(Train *head) * @param p1 various bitstuffed elements * - p1 (bit 0 - 19) source vehicle index * - p1 (bit 20) move all vehicles following the source vehicle + * - p1 (bit 21) this is a virtual vehicle (for creating TemplateVehicles) * @param p2 what wagon to put the source wagon AFTER, XXX - INVALID_VEHICLE to make a new line * @param text unused * @return the cost of this operation or an error @@ -1222,10 +1225,14 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u if (!move_chain && dst != NULL && dst->IsRearDualheaded() && src == dst->other_multiheaded_part) return CommandCost(); /* Check if all vehicles in the source train are stopped inside a depot. */ - if (!src_head->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT); + /* Do this check only if the vehicle to be moved is non-virtual */ + if ( !HasBit(p1, 21) ) + if (!src_head->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT); /* Check if all vehicles in the destination train are stopped inside a depot. */ - if (dst_head != NULL && !dst_head->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT); + /* Do this check only if the destination vehicle is non-virtual */ + if ( !HasBit(p1, 21) ) + if (dst_head != NULL && !dst_head->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT); /* First make a backup of the order of the trains. That way we can do * whatever we want with the order and later on easily revert. */ @@ -1334,8 +1341,11 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u if (dst_head != NULL) dst_head->First()->MarkDirty(); /* We are undoubtedly changing something in the depot and train list. */ - InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile); - InvalidateWindowClassesData(WC_TRAINS_LIST, 0); + /* But only if the moved vehicle is not virtual */ + if ( !HasBit(src->subtype, GVSF_VIRTUAL) ) { + InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile); + InvalidateWindowClassesData(WC_TRAINS_LIST, 0); + } } else { /* We don't want to execute what we're just tried. */ RestoreTrainBackup(original_src); @@ -1418,8 +1428,11 @@ CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data, uint3 NormaliseTrainHead(new_head); /* We are undoubtedly changing something in the depot and train list. */ - InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); - InvalidateWindowClassesData(WC_TRAINS_LIST, 0); + /* Unless its a virtual train */ + if ( !HasBit(v->subtype, GVSF_VIRTUAL) ) { + InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); + InvalidateWindowClassesData(WC_TRAINS_LIST, 0); + } /* Actually delete the sold 'goods' */ delete sell_head; @@ -3741,6 +3754,16 @@ static bool TrainCheckIfLineEnds(Train *v, bool reverse) return true; } +/* Calculate the summed up value of all parts of a train */ +Money Train::CalculateCurrentOverallValue() const +{ + Money ovr_value = 0; + const Train *v = this; + do { + ovr_value += v->value; + } while ( (v=v->GetNextVehicle()) != NULL ); + return ovr_value; +} static bool TrainLocoHandler(Train *v, bool mode) { @@ -4035,3 +4058,158 @@ Trackdir Train::GetVehicleTrackdir() const return TrackDirectionToTrackdir(FindFirstTrack(this->track), this->direction); } + + +/* Get the pixel-width of the image that is used for the train vehicle + * @return: the image width number in pixel + */ +int GetDisplayImageWidth(Train *t, Point *offset) +{ + int reference_width = TRAININFO_DEFAULT_VEHICLE_WIDTH; + int vehicle_pitch = 0; + + const Engine *e = Engine::Get(t->engine_type); + if (e->grf_prop.grffile != NULL && is_custom_sprite(e->u.rail.image_index)) { + reference_width = e->grf_prop.grffile->traininfo_vehicle_width; + vehicle_pitch = e->grf_prop.grffile->traininfo_vehicle_pitch; + } + + if (offset != NULL) { + offset->x = reference_width / 2; + offset->y = vehicle_pitch; + } + //printf(" refwid:%d gdiw.cachedvehlen(%d):%d ", reference_width, this->engine_type, this->gcache.cached_veh_length); + return t->gcache.cached_veh_length * reference_width / VEHICLE_LENGTH; +} + +Train* CmdBuildVirtualRailWagon(const Engine *e) +{ + const RailVehicleInfo *rvi = &e->u.rail; + + Train *v = new Train(); + + v->x_pos = 0; + v->y_pos = 0; + + v->spritenum = rvi->image_index; + + v->engine_type = e->index; + v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback + + v->direction = DIR_W; + v->tile = 0;//INVALID_TILE; + + v->owner = _current_company; + v->track = TRACK_BIT_DEPOT; + v->vehstatus = VS_HIDDEN | VS_DEFPAL; + + v->SetWagon(); + v->SetFreeWagon(); + + v->cargo_type = e->GetDefaultCargoType(); + v->cargo_cap = rvi->capacity; + + v->railtype = rvi->railtype; + + v->build_year = _cur_year; + v->cur_image = SPR_IMG_QUERY; + v->random_bits = VehicleRandomBits(); + + v->group_id = DEFAULT_GROUP; + + AddArticulatedParts(v); + + _new_vehicle_id = v->index; + + // from revision r22xxx + // VehicleMove(v, false); + // new + v->UpdateViewport(true, false); + + v->First()->ConsistChanged(ConsistChangeFlags::CCF_ARRANGE); + //UpdateTrainGroupID(v->First()); + + CheckConsistencyOfArticulatedVehicle(v); + + /* The GVSF_VIRTUAL flag is used to prevent depot-tile sanity checks */ + SetBit(v->subtype, GVSF_VIRTUAL); + +// GroupStatistics::CountVehicle( v, -1 ); + + return v; +} + +/** + * Build a railroad vehicle. + * @param tile tile of the depot where rail-vehicle is built. + * @param flags type of operation. + * @param e the engine to build. + * @param data bit 0 prevents any free cars from being added to the train. + * @param ret[out] the vehicle that has been built. + * @return the cost of this operation or an error. + */ +Train* CmdBuildVirtualRailVehicle(EngineID eid) +{ + if ( !IsEngineBuildable(eid, VEH_TRAIN, _current_company) ) return 0; + const Engine* e = Engine::Get(eid); + const RailVehicleInfo *rvi = &e->u.rail; + + int num_vehicles = (e->u.rail.railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) + CountArticulatedParts(eid, false); + if ( !Train::CanAllocateItem(num_vehicles) ) return 0; + if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildVirtualRailWagon(e); + + Train *v = new Train(); + + v->x_pos = 0; + v->y_pos = 0; + + v->direction = DIR_W; + v->tile = 0;//INVALID_TILE; + v->owner = _current_company; + v->track = TRACK_BIT_DEPOT; + v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL; + v->spritenum = rvi->image_index; + v->cargo_type = e->GetDefaultCargoType(); + v->cargo_cap = rvi->capacity; + v->last_station_visited = INVALID_STATION; + + v->engine_type = e->index; + v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback + + v->reliability = e->reliability; + v->reliability_spd_dec = e->reliability_spd_dec; + v->max_age = e->GetLifeLengthInDays(); + + v->railtype = rvi->railtype; + _new_vehicle_id = v->index; + + v->cur_image = SPR_IMG_QUERY; + v->random_bits = VehicleRandomBits(); + + v->group_id = DEFAULT_GROUP; + + v->SetFrontEngine(); + v->SetEngine(); + + // from revision r22xxx +// VehicleMove(v, false); + // new + v->UpdateViewport(true, false); + + if (rvi->railveh_type == RAILVEH_MULTIHEAD) { + AddRearEngineToMultiheadedTrain(v); + } else { + AddArticulatedParts(v); + } + + v->ConsistChanged(ConsistChangeFlags::CCF_ARRANGE); + //UpdateTrainGroupID(v); + + CheckConsistencyOfArticulatedVehicle(v); + + SetBit(v->subtype, GVSF_VIRTUAL); + +// GroupStatistics::CountVehicle( v, -1 ); + + return v; +} diff --git a/src/vehicle.cpp b/src/vehicle.cpp index a482520f25..d9f3afbd30 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -57,6 +57,8 @@ #include "safeguards.h" +#include "tbtr_template_vehicle_func.h" + #define GEN_HASH(x, y) ((GB((y), 6 + ZOOM_LVL_SHIFT, 6) << 6) + GB((x), 7 + ZOOM_LVL_SHIFT, 6)) VehicleID _new_vehicle_id; @@ -626,6 +628,13 @@ void ResetVehicleColourMap() typedef SmallMap AutoreplaceMap; static AutoreplaceMap _vehicles_to_autoreplace; +/** + * List of vehicles that are issued for template replacement this tick. + * Mapping is {vehicle : leave depot after replacement} + */ +typedef SmallMap TemplateReplacementMap; +static TemplateReplacementMap _vehicles_to_templatereplace; + void InitializeVehicles() { _vehicles_to_autoreplace.Reset(); @@ -828,14 +837,25 @@ Vehicle::~Vehicle() */ void VehicleEnteredDepotThisTick(Vehicle *v) { - /* Vehicle should stop in the depot if it was in 'stopping' state */ - _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED); + /* Template Replacement Setup stuff */ + bool stayInDepot = v->current_order.GetDepotActionType(); + TemplateReplacement *tr = GetTemplateReplacementByGroupID(v->group_id); + if ( tr ) { + if ( stayInDepot ) _vehicles_to_templatereplace[(Train*)v] = true; + else _vehicles_to_templatereplace[(Train*)v] = false; + } + /* Moved the assignment for auto replacement here to prevent auto replacement + * from happening if template replacement is also scheduled */ + else + /* Vehicle should stop in the depot if it was in 'stopping' state */ + _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED); /* We ALWAYS set the stopped state. Even when the vehicle does not plan on * stopping in the depot, so we stop it to ensure that it will not reserve * the path out of the depot before we might autoreplace it to a different * engine. The new engine would not own the reserved path we store that we * stopped the vehicle, so autoreplace can start it again */ + v->vehstatus |= VS_STOPPED; } @@ -877,6 +897,7 @@ static void RunVehicleDayProc() void CallVehicleTicks() { _vehicles_to_autoreplace.Clear(); + _vehicles_to_templatereplace.Clear(); RunVehicleDayProc(); @@ -953,6 +974,7 @@ void CallVehicleTicks() } } + /* do Auto Replacement */ Backup cur_company(_current_company, FILE_LINE); for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) { v = it->first; @@ -997,8 +1019,24 @@ void CallVehicleTicks() SetDParam(1, error_message); AddVehicleAdviceNewsItem(message, v->index); } - cur_company.Restore(); + + /* do Template Replacement */ + Backup tmpl_cur_company(_current_company, FILE_LINE); + for (TemplateReplacementMap::iterator it = _vehicles_to_templatereplace.Begin(); it != _vehicles_to_templatereplace.End(); it++) { + + Train *t = it->first; + + tmpl_cur_company.Change(t->owner); + + bool stayInDepot = it->second; + + it->first->vehstatus |= VS_STOPPED; + CmdTemplateReplaceVehicle(t, stayInDepot, DC_EXEC); + /* Redraw main gui for changed statistics */ + SetWindowClassesDirty(WC_TEMPLATEGUI_MAIN); + } + tmpl_cur_company.Restore(); } /** diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 59584da788..da9cce3639 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -26,6 +26,8 @@ #include #include +CommandCost CmdRefitVehicle(TileIndex, DoCommandFlag, uint32, uint32, const char*); + /** Vehicle status bits in #Vehicle::vehstatus. */ enum VehStatus { VS_HIDDEN = 0x01, ///< Vehicle is not visible. @@ -115,6 +117,7 @@ enum GroundVehicleSubtypeFlags { GVSF_ENGINE = 3, ///< Engine that can be front engine, but might be placed behind another engine (not used for road vehicles). GVSF_FREE_WAGON = 4, ///< First in a wagon chain (in depot) (not used for road vehicles). GVSF_MULTIHEADED = 5, ///< Engine is multiheaded (not used for road vehicles). + GVSF_VIRTUAL = 6, ///< Used for virtual trains during template design, it is needed to skip checks for tile or depot status }; /** Cached often queried values common to all vehicles. */ @@ -514,6 +517,7 @@ public: Money GetDisplayProfitLastYear() const { return (this->profit_last_year >> 8); } void SetNext(Vehicle *next); + inline void SetFirst(Vehicle *f) { this->first=f; } /** * Get the next vehicle of this vehicle. diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index 3b664defb6..c8fee79095 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -422,6 +422,7 @@ static CommandCost RefitVehicle(Vehicle *v, bool only_this, uint8 num_vehicles, * @param p2 various bitstuffed elements * - p2 = (bit 0-4) - New cargo type to refit to. * - p2 = (bit 6) - Automatic refitting. + * - p2 = (bit 5) - Is a virtual train (used by template replacement to allow refitting without stopped-in-depot checks) * - p2 = (bit 7) - Refit only this vehicle. Used only for cloning vehicles. * - p2 = (bit 8-15) - New cargo subtype to refit to. 0xFF means to try keeping the same subtype according to GetBestFittingSubType(). * - p2 = (bit 16-23) - Number of vehicles to refit (not counting articulated parts). Zero means all vehicles. @@ -444,12 +445,17 @@ CommandCost CmdRefitVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint if (ret.Failed()) return ret; bool auto_refit = HasBit(p2, 6); + bool is_virtual_train = HasBit(p2, 5); bool free_wagon = v->type == VEH_TRAIN && Train::From(front)->IsFreeWagon(); // used by autoreplace/renew /* Don't allow shadows and such to be refitted. */ if (v != front && (v->type == VEH_SHIP || v->type == VEH_AIRCRAFT)) return CMD_ERROR; /* Allow auto-refitting only during loading and normal refitting only in a depot. */ + if ( ! is_virtual_train ) { + if (!free_wagon && (!auto_refit || !front->current_order.IsType(OT_LOADING)) && !front->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type); + if (front->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_VEHICLE_IS_DESTROYED); + } if ((flags & DC_QUERY_COST) == 0 && // used by the refit GUI, including the order refit GUI. !free_wagon && // used by autoreplace/renew (!auto_refit || !front->current_order.IsType(OT_LOADING)) && // refit inside stations @@ -499,7 +505,9 @@ CommandCost CmdRefitVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint InvalidateWindowData(WC_VEHICLE_DETAILS, front->index); InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0); } - SetWindowDirty(WC_VEHICLE_DEPOT, front->tile); + /* virtual vehicles get their cargo changed by the TemplateCreateWindow, so set this dirty instead of a depot window */ + if ( HasBit(v->subtype, GVSF_VIRTUAL) ) SetWindowClassesDirty(WC_CREATE_TEMPLATE); + else SetWindowDirty(WC_VEHICLE_DEPOT, front->tile); } else { /* Always invalidate the cache; querycost might have filled it. */ v->InvalidateNewGRFCacheOfChain(); diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 10f1d952da..9dba03481a 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -37,11 +37,11 @@ #include "engine_func.h" #include "station_base.h" #include "tilehighlight_func.h" +#include "tbtr_template_gui_main.h" #include "zoom_func.h" #include "safeguards.h" - Sorting _sorting; static GUIVehicleList::SortFunction VehicleNumberSorter; @@ -168,6 +168,7 @@ DropDownList *BaseVehicleListWindow::BuildActionDropdownList(bool show_autorepla { DropDownList *list = new DropDownList(); + *list->Append() = new DropDownListStringItem(STR_TMPL_TEMPLATE_REPLACEMENT, ADI_TEMPLATE_REPLACE, false); if (show_autoreplace) *list->Append() = new DropDownListStringItem(STR_VEHICLE_LIST_REPLACE_VEHICLES, ADI_REPLACE, false); *list->Append() = new DropDownListStringItem(STR_VEHICLE_LIST_SEND_FOR_SERVICING, ADI_SERVICE, false); *list->Append() = new DropDownListStringItem(this->vehicle_depot_name[this->vli.vtype], ADI_DEPOT, false); @@ -400,6 +401,7 @@ struct RefitWindow : public Window { VehicleID selected_vehicle; ///< First vehicle in the current selection. uint8 num_vehicles; ///< Number of selected vehicles. bool auto_refit; ///< Select cargo for auto-refitting. + bool is_virtual_train; ///< TemplateReplacement, whether the selected vehicle is virtual /** * Collects all (cargo, subcargo) refit options of a vehicle chain. @@ -581,11 +583,12 @@ struct RefitWindow : public Window { return &l[this->sel[1]]; } - RefitWindow(WindowDesc *desc, const Vehicle *v, VehicleOrderID order, bool auto_refit) : Window(desc) + RefitWindow(WindowDesc *desc, const Vehicle *v, VehicleOrderID order, bool auto_refit, bool is_virtual) : Window(desc) { this->sel[0] = -1; this->sel[1] = 0; this->auto_refit = auto_refit; + this->is_virtual_train = is_virtual; this->order = order; this->CreateNestedTree(); @@ -949,9 +952,9 @@ struct RefitWindow : public Window { if (this->order == INVALID_VEH_ORDER_ID) { bool delete_window = this->selected_vehicle == v->index && this->num_vehicles == UINT8_MAX; - if (DoCommandP(v->tile, this->selected_vehicle, this->cargo->cargo | this->cargo->subtype << 8 | this->num_vehicles << 16, GetCmdRefitVeh(v)) && delete_window) delete this; + if (DoCommandP(v->tile, this->selected_vehicle, this->cargo->cargo | this->cargo->subtype << 8 | this->num_vehicles << 16 | this->is_virtual_train << 5, GetCmdRefitVeh(v)) && delete_window) delete this; } else { - if (DoCommandP(v->tile, v->index, this->cargo->cargo | this->order << 16, CMD_ORDER_REFIT)) delete this; + if (DoCommandP(v->tile, v->index, this->cargo->cargo | this->cargo->subtype << 8 | this->order << 16 | this->is_virtual_train << 5, CMD_ORDER_REFIT)) delete this; } } break; @@ -1032,10 +1035,10 @@ static WindowDesc _vehicle_refit_desc( * @param parent the parent window of the refit window * @param auto_refit Choose cargo for auto-refitting */ -void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order, Window *parent, bool auto_refit) +void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order, Window *parent, bool auto_refit, bool is_virtual_train) { DeleteWindowById(WC_VEHICLE_REFIT, v->index); - RefitWindow *w = new RefitWindow(&_vehicle_refit_desc, v, order, auto_refit); + RefitWindow *w = new RefitWindow(&_vehicle_refit_desc, v, order, auto_refit, is_virtual_train); w->parent = parent; } @@ -1663,6 +1666,9 @@ public: case ADI_REPLACE: // Replace window ShowReplaceGroupVehicleWindow(ALL_GROUP, this->vli.vtype); break; + case ADI_TEMPLATE_REPLACE: + ShowTemplateReplaceWindow(this->unitnumber_digits, this->resize.step_height); + break; case ADI_SERVICE: // Send for servicing case ADI_DEPOT: // Send to Depots DoCommandP(0, DEPOT_MASS_SEND | (index == ADI_SERVICE ? DEPOT_SERVICE : (DepotCommand)0), this->window_number, GetCmdSendToDepot(this->vli.vtype)); diff --git a/src/vehicle_gui.h b/src/vehicle_gui.h index 83e098dcd9..523fe381e0 100644 --- a/src/vehicle_gui.h +++ b/src/vehicle_gui.h @@ -19,7 +19,7 @@ #include "engine_type.h" #include "company_type.h" -void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order, Window *parent, bool auto_refit = false); +void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order, Window *parent, bool auto_refit = false, bool is_virtual_train = false); /** The tabs in the train details window */ enum TrainDetailsWindowTabs { diff --git a/src/vehicle_gui_base.h b/src/vehicle_gui_base.h index 1c03f7b34d..6bbb952882 100644 --- a/src/vehicle_gui_base.h +++ b/src/vehicle_gui_base.h @@ -27,6 +27,7 @@ struct BaseVehicleListWindow : public Window { VehicleListIdentifier vli; ///< Identifier of the vehicle list we want to currently show. enum ActionDropdownItem { + ADI_TEMPLATE_REPLACE, ADI_REPLACE, ADI_SERVICE, ADI_DEPOT, diff --git a/src/vehiclelist.cpp b/src/vehiclelist.cpp index 7e42b25aa2..c063ae5698 100644 --- a/src/vehiclelist.cpp +++ b/src/vehiclelist.cpp @@ -147,7 +147,7 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli case VL_GROUP_LIST: if (vli.index != ALL_GROUP) { FOR_ALL_VEHICLES(v) { - if (v->type == vli.vtype && v->IsPrimaryVehicle() && + if (!HasBit(v->subtype, GVSF_VIRTUAL) && v->type == vli.vtype && v->IsPrimaryVehicle() && v->owner == vli.company && GroupIsInGroup(v->group_id, vli.index)) { *list->Append() = v; } @@ -158,7 +158,7 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli case VL_STANDARD: FOR_ALL_VEHICLES(v) { - if (v->type == vli.vtype && v->owner == vli.company && v->IsPrimaryVehicle()) { + if (!HasBit(v->subtype, GVSF_VIRTUAL) && v->type == vli.vtype && v->owner == vli.company && v->IsPrimaryVehicle()) { *list->Append() = v; } } diff --git a/src/viewport.cpp b/src/viewport.cpp index a1bb2c81d1..2b3fe6e272 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -2189,9 +2189,10 @@ bool HandleViewportClicked(const ViewPort *vp, int x, int y) DEBUG(misc, 2, "Vehicle %d (index %d) at %p", v->unitnumber, v->index, v); if (IsCompanyBuildableVehicleType(v)) { v = v->First(); + WindowClass wc = _thd.GetCallbackWnd()->window_class; if (_ctrl_pressed && v->owner == _local_company) { StartStopVehicle(v, true); - } else { + } else if ( wc != WC_CREATE_TEMPLATE && wc != WC_TEMPLATEGUI_MAIN) { ShowVehicleViewWindow(v); } } diff --git a/src/widgets/build_vehicle_widget.h b/src/widgets/build_vehicle_widget.h index ae548587e2..110a995578 100644 --- a/src/widgets/build_vehicle_widget.h +++ b/src/widgets/build_vehicle_widget.h @@ -26,6 +26,7 @@ enum BuildVehicleWidgets { WID_BV_SHOW_HIDE, ///< Button to hide or show the selected engine. WID_BV_BUILD_SEL, ///< Build button. WID_BV_RENAME, ///< Rename button. + BUILD_VEHICLE_WIDGET_BUILD, /// TODO: own }; #endif /* WIDGETS_BUILD_VEHICLE_WIDGET_H */ diff --git a/src/window_type.h b/src/window_type.h index 809e81d485..14d10598d9 100644 --- a/src/window_type.h +++ b/src/window_type.h @@ -681,6 +681,12 @@ enum WindowClass { */ WC_SAVE_PRESET, + WC_TEMPLATEGUI_MAIN, + WC_TEMPLATEGUI_RPLALL, + WC_BUILD_VIRTUAL_TRAIN, + WC_CREATE_TEMPLATE, + + WC_INVALID = 0xFFFF, ///< Invalid window. }; From 6be2efc08410545f653956615cf7de0d8c268cd4 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 14 Feb 2016 00:52:42 +0000 Subject: [PATCH 05/15] Update from KeldorKatarn branch This approximately corresponds to 971ba4928a5c7c7916fea55d91a3b6dd5bba140c, excluding the different virtual train build GUI, but including the basic changes to the original train build GUI for multiplayer to work. Fixup --- src/command.cpp | 39 ++ src/command_func.h | 8 + src/command_type.h | 19 + src/ground_vehicle.hpp | 16 + src/network/network_command.cpp | 4 + src/tbtr_template_gui_create.cpp | 214 +++++--- src/tbtr_template_gui_create_virtualtrain.cpp | 31 +- src/tbtr_template_gui_main.cpp | 243 +++++---- src/tbtr_template_gui_replaceall.cpp | 5 +- src/tbtr_template_vehicle.h | 10 +- src/tbtr_template_vehicle_func.cpp | 266 +--------- src/tbtr_template_vehicle_func.h | 21 +- src/train_cmd.cpp | 279 ++++++++++- src/vehicle.cpp | 4 +- src/vehicle_cmd.cpp | 467 +++++++++++++++++- 15 files changed, 1167 insertions(+), 459 deletions(-) diff --git a/src/command.cpp b/src/command.cpp index 959610cd28..d43b3e5115 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -106,6 +106,8 @@ CommandProc CmdDecreaseLoan; CommandProc CmdWantEnginePreview; +CommandProc CmdSetVehicleUnitNumber; + CommandProc CmdRenameVehicle; CommandProc CmdRenameEngine; @@ -175,10 +177,27 @@ CommandProc CmdRemoveSignalTrack; CommandProc CmdSetAutoReplace; +CommandProc CmdToggleReuseDepotVehicles; +CommandProc CmdToggleKeepRemainingVehicles; +CommandProc CmdToggleRefitAsTemplate; + +CommandProc CmdVirtualTrainFromTemplateVehicle; +CommandProc CmdVirtualTrainFromTrain; +CommandProc CmdDeleteVirtualTrain; +CommandProc CmdBuildVirtualRailVehicle; +CommandProc CmdReplaceTemplateVehicle; + +CommandProc CmdTemplateVehicleFromTrain; +CommandProc CmdDeleteTemplateVehicle; + +CommandProc CmdIssueTemplateReplacement; +CommandProc CmdDeleteTemplateReplacement; + CommandProc CmdCloneVehicle; CommandProc CmdStartStopVehicle; CommandProc CmdMassStartStopVehicle; CommandProc CmdAutoreplaceVehicle; +CommandProc CmdTemplateReplaceVehicle; CommandProc CmdDepotSellAllVehicles; CommandProc CmdDepotMassAutoReplace; @@ -267,6 +286,8 @@ static const Command _command_proc_table[] = { DEF_CMD(CmdWantEnginePreview, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_WANT_ENGINE_PREVIEW + DEF_CMD(CmdSetVehicleUnitNumber, 0, CMDT_OTHER_MANAGEMENT ), // CMD_SET_VEHICLE_UNIT_NUMBER + DEF_CMD(CmdRenameVehicle, 0, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_VEHICLE DEF_CMD(CmdRenameEngine, CMD_SERVER, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_ENGINE @@ -334,10 +355,28 @@ static const Command _command_proc_table[] = { DEF_CMD(CmdChangeSetting, CMD_SERVER, CMDT_SERVER_SETTING ), // CMD_CHANGE_SETTING DEF_CMD(CmdChangeCompanySetting, 0, CMDT_COMPANY_SETTING ), // CMD_CHANGE_COMPANY_SETTING DEF_CMD(CmdSetAutoReplace, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_SET_AUTOREPLACE + + DEF_CMD(CmdToggleReuseDepotVehicles, CMD_ALL_TILES, CMDT_VEHICLE_MANAGEMENT ), // CMD_TOGGLE_REUSE_DEPOT_VEHICLES + DEF_CMD(CmdToggleKeepRemainingVehicles, CMD_ALL_TILES, CMDT_VEHICLE_MANAGEMENT ), // CMD_TOGGLE_KEEP_REMAINING_VEHICLES + DEF_CMD(CmdToggleRefitAsTemplate, CMD_ALL_TILES, CMDT_VEHICLE_MANAGEMENT ), // CMD_TOGGLE_REFIT_AS_TEMPLATE + + DEF_CMD(CmdVirtualTrainFromTemplateVehicle, CMD_ALL_TILES, CMDT_VEHICLE_MANAGEMENT ), // CMD_VIRTUAL_TRAIN_FROM_TEMPLATE_VEHICLE + DEF_CMD(CmdVirtualTrainFromTrain, CMD_ALL_TILES, CMDT_VEHICLE_MANAGEMENT ), // CMD_VIRTUAL_TRAIN_FROM_TRAIN + DEF_CMD(CmdDeleteVirtualTrain, CMD_ALL_TILES, CMDT_VEHICLE_MANAGEMENT ), // CMD_DELETE_VIRTUAL_TRAIN + DEF_CMD(CmdBuildVirtualRailVehicle, CMD_ALL_TILES, CMDT_VEHICLE_MANAGEMENT ), // CMD_BUILD_VIRTUAL_RAIL_VEHICLE + DEF_CMD(CmdReplaceTemplateVehicle, CMD_ALL_TILES, CMDT_VEHICLE_MANAGEMENT ), // CMD_REPLACE_TEMPLATE_VEHICLE + + DEF_CMD(CmdTemplateVehicleFromTrain, CMD_ALL_TILES, CMDT_VEHICLE_MANAGEMENT ), // CMD_CLONE_TEMPLATE_VEHICLE_FROM_TRAIN + DEF_CMD(CmdDeleteTemplateVehicle, CMD_ALL_TILES, CMDT_VEHICLE_MANAGEMENT ), // CMD_DELETE_TEMPLATE_VEHICLE + + DEF_CMD(CmdIssueTemplateReplacement, CMD_ALL_TILES, CMDT_VEHICLE_MANAGEMENT ), // CMD_ISSUE_TEMPLATE_REPLACEMENT + DEF_CMD(CmdDeleteTemplateReplacement, CMD_ALL_TILES, CMDT_VEHICLE_MANAGEMENT ), // CMD_DELETE_TEMPLATE_REPLACEMENT + DEF_CMD(CmdCloneVehicle, CMD_NO_TEST, CMDT_VEHICLE_CONSTRUCTION ), // CMD_CLONE_VEHICLE; NewGRF callbacks influence building and refitting making it impossible to correctly estimate the cost DEF_CMD(CmdStartStopVehicle, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_START_STOP_VEHICLE DEF_CMD(CmdMassStartStopVehicle, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_MASS_START_STOP DEF_CMD(CmdAutoreplaceVehicle, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_AUTOREPLACE_VEHICLE + DEF_CMD(CmdTemplateReplaceVehicle, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_TEMPLATE_REPLACE_VEHICLE DEF_CMD(CmdDepotSellAllVehicles, 0, CMDT_VEHICLE_CONSTRUCTION ), // CMD_DEPOT_SELL_ALL_VEHICLES DEF_CMD(CmdDepotMassAutoReplace, 0, CMDT_VEHICLE_CONSTRUCTION ), // CMD_DEPOT_MASS_AUTOREPLACE DEF_CMD(CmdCreateGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_CREATE_GROUP diff --git a/src/command_func.h b/src/command_func.h index c4cc51e3da..d719aba570 100644 --- a/src/command_func.h +++ b/src/command_func.h @@ -125,4 +125,12 @@ CommandCallback CcFoundRandomTown; CommandCallback CcBuildPrimaryVehicle; CommandCallback CcStartStopVehicle; +/* tbtr_template_gui_create.cpp */ +CommandCallback CcSetVirtualTrain; +CommandCallback CcVirtualTrainWaggonsMoved; +CommandCallback CcDeleteVirtualTrain; + +/* tbtr_template_gui_create_virtualtrain.cpp */ +CommandCallback CcAddVirtualEngine; + #endif /* COMMAND_FUNC_H */ diff --git a/src/command_type.h b/src/command_type.h index f318216acc..3976620f4a 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -240,6 +240,8 @@ enum Commands { CMD_WANT_ENGINE_PREVIEW, ///< confirm the preview of an engine + CMD_SET_VEHICLE_UNIT_NUMBER, ///< sets the unit number of a vehicle + CMD_RENAME_VEHICLE, ///< rename a whole vehicle CMD_RENAME_ENGINE, ///< rename a engine (in the engine list) CMD_RENAME_COMPANY, ///< change the company name @@ -306,10 +308,27 @@ enum Commands { CMD_SET_AUTOREPLACE, ///< set an autoreplace entry + CMD_TOGGLE_REUSE_DEPOT_VEHICLES, ///< toggle 'reuse depot vehicles' on template + CMD_TOGGLE_KEEP_REMAINING_VEHICLES, ///< toggle 'keep remaining vehicles' on template + CMD_TOGGLE_REFIT_AS_TEMPLATE, ///< toggle 'refit as template' on template + + CMD_VIRTUAL_TRAIN_FROM_TEMPLATE_VEHICLE, ///< Creates a virtual train from a template + CMD_VIRTUAL_TRAIN_FROM_TRAIN, ///< Creates a virtual train from a regular train + CMD_DELETE_VIRTUAL_TRAIN, ///< Delete a virtual train + CMD_BUILD_VIRTUAL_RAIL_VEHICLE, ///< Build a virtual train + CMD_REPLACE_TEMPLATE_VEHICLE, ///< Replace a template vehicle with another one based on a virtual train + + CMD_CLONE_TEMPLATE_VEHICLE_FROM_TRAIN, ///< clone a train and create a new template vehicle based on it + CMD_DELETE_TEMPLATE_VEHICLE, ///< delete a template vehicle + + CMD_ISSUE_TEMPLATE_REPLACEMENT, ///< issue a template replacement for a vehicle group + CMD_DELETE_TEMPLATE_REPLACEMENT, ///< delete a template replacement from a vehicle group + CMD_CLONE_VEHICLE, ///< clone a vehicle CMD_START_STOP_VEHICLE, ///< start or stop a vehicle CMD_MASS_START_STOP, ///< start/stop all vehicles (in a depot) CMD_AUTOREPLACE_VEHICLE, ///< replace/renew a vehicle while it is in a depot + CMD_TEMPLATE_REPLACE_VEHICLE, ///< template replace a vehicle while it is in a depot CMD_DEPOT_SELL_ALL_VEHICLES, ///< sell all vehicles which are in a given depot CMD_DEPOT_MASS_AUTOREPLACE, ///< force the autoreplace to take action in a given depot diff --git a/src/ground_vehicle.hpp b/src/ground_vehicle.hpp index 56b97875fc..b39600796e 100644 --- a/src/ground_vehicle.hpp +++ b/src/ground_vehicle.hpp @@ -295,6 +295,16 @@ struct GroundVehicle : public SpecializedVehicle { */ inline void ClearFreeWagon() { ClrBit(this->subtype, GVSF_FREE_WAGON); } + /** + * Set a vehicle as a virtual vehicle. + */ + inline void SetVirtual() { SetBit(this->subtype, GVSF_VIRTUAL); } + + /** + * Clear a vehicle from being a virtual vehicle. + */ + inline void ClearVirtual() { ClrBit(this->subtype, GVSF_VIRTUAL); } + /** * Set a vehicle as a multiheaded engine. */ @@ -329,6 +339,12 @@ struct GroundVehicle : public SpecializedVehicle { */ inline bool IsMultiheaded() const { return HasBit(this->subtype, GVSF_MULTIHEADED); } + /** + * Tell if we are dealing with a virtual vehicle (used for templates). + * @return True if the vehicle is a virtual vehicle. + */ + inline bool IsVirtual() const { return HasBit(this->subtype, GVSF_VIRTUAL); } + /** * Tell if we are dealing with the rear end of a multiheaded engine. * @return True if the engine is the rear part of a dualheaded engine. diff --git a/src/network/network_command.cpp b/src/network/network_command.cpp index 6e5458fd86..6862191473 100644 --- a/src/network/network_command.cpp +++ b/src/network/network_command.cpp @@ -51,6 +51,10 @@ static CommandCallback * const _callback_table[] = { /* 0x19 */ CcStartStopVehicle, /* 0x1A */ CcGame, /* 0x1B */ CcAddVehicleNewGroup, + /* 0x1C */ CcSetVirtualTrain, + /* 0x1D */ CcVirtualTrainWaggonsMoved, + /* 0x1E */ CcDeleteVirtualTrain, + /* 0x1F */ CcAddVirtualEngine, }; /** diff --git a/src/tbtr_template_gui_create.cpp b/src/tbtr_template_gui_create.cpp index c2dc436cab..c7a475d1ac 100644 --- a/src/tbtr_template_gui_create.cpp +++ b/src/tbtr_template_gui_create.cpp @@ -43,9 +43,10 @@ uint16 TRAIN_FRONT_SPACE = 16; enum TemplateReplaceWindowWidgets { TCW_CAPTION, - TCW_MATRIX_NEW_TMPL, + TCW_NEW_TMPL_PANEL, TCW_INFO_PANEL, - TCW_SCROLLBAR_NEW_TMPL, + TCW_SCROLLBAR_H_NEW_TMPL, + TCW_SCROLLBAR_V_NEW_TMPL, TCW_SELL_TMPL, TCW_NEW, TCW_OK, @@ -59,23 +60,25 @@ static const NWidgetPart _widgets[] = { NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, TCW_CAPTION), SetDataTip(STR_TMPL_CREATEGUI_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), - NWidget(WWT_MATRIX, COLOUR_GREY, TCW_MATRIX_NEW_TMPL), SetMinimalSize(216, 60), SetFill(1, 0), SetDataTip(0x1, STR_REPLACE_HELP_LEFT_ARRAY), SetResize(1, 0), SetScrollbar(TCW_SCROLLBAR_NEW_TMPL), - NWidget(WWT_PANEL, COLOUR_GREY, TCW_INFO_PANEL), SetMinimalSize(216,80), SetResize(1,1), EndContainer(), - NWidget(NWID_HSCROLLBAR, COLOUR_GREY, TCW_SCROLLBAR_NEW_TMPL), SetResize(1,0), + NWidget(WWT_PANEL, COLOUR_GREY, TCW_NEW_TMPL_PANEL), SetMinimalSize(250, 30), SetResize(1, 0), SetScrollbar(TCW_SCROLLBAR_H_NEW_TMPL), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, TCW_INFO_PANEL), SetMinimalSize(250, 100), SetResize(1, 1), SetScrollbar(TCW_SCROLLBAR_V_NEW_TMPL), EndContainer(), + NWidget(NWID_HSCROLLBAR, COLOUR_GREY, TCW_SCROLLBAR_H_NEW_TMPL), EndContainer(), - NWidget(WWT_IMGBTN, COLOUR_GREY, TCW_SELL_TMPL), SetDataTip(0x0, STR_NULL), SetMinimalSize(23,23), SetResize(0, 1), SetFill(0, 1), + NWidget(WWT_IMGBTN, COLOUR_GREY, TCW_SELL_TMPL), SetMinimalSize(40, 40), SetDataTip(0x0, STR_NULL), SetResize(0, 1), SetFill(0, 1), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, TCW_SCROLLBAR_V_NEW_TMPL), EndContainer(), NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TCW_OK), SetMinimalSize(52, 12), SetResize(1,0), SetDataTip(STR_TMPL_CONFIRM, STR_TMPL_CONFIRM), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TCW_NEW), SetMinimalSize(52, 12), SetResize(1,0), SetDataTip(STR_TMPL_NEW, STR_TMPL_NEW), - NWidget(WWT_TEXTBTN, COLOUR_GREY, TCW_CLONE), SetMinimalSize(52, 12), SetResize(1,0), SetDataTip(STR_TMPL_CREATE_CLONE_VEH, STR_TMPL_CREATE_CLONE_VEH), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TCW_REFIT), SetMinimalSize(52, 12), SetResize(1,0), SetDataTip(STR_TMPL_REFIT, STR_TMPL_REFIT), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TCW_CANCEL), SetMinimalSize(52, 12), SetResize(1,0), SetDataTip(STR_TMPL_CANCEL, STR_TMPL_CANCEL), - NWidget(WWT_RESIZEBOX, COLOUR_GREY), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TCW_OK), SetMinimalSize(52, 12), SetResize(1, 0), SetDataTip(STR_TMPL_CONFIRM, STR_TMPL_CONFIRM), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TCW_NEW), SetMinimalSize(52, 12), SetResize(1, 0), SetDataTip(STR_TMPL_NEW, STR_TMPL_NEW), + NWidget(WWT_TEXTBTN, COLOUR_GREY, TCW_CLONE), SetMinimalSize(52, 12), SetResize(1, 0), SetDataTip(STR_TMPL_CREATE_CLONE_VEH, STR_TMPL_CREATE_CLONE_VEH), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TCW_REFIT), SetMinimalSize(52, 12), SetResize(1, 0), SetDataTip(STR_TMPL_REFIT, STR_TMPL_REFIT), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TCW_CANCEL), SetMinimalSize(52, 12), SetResize(1, 0), SetDataTip(STR_TMPL_CANCEL, STR_TMPL_CANCEL), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), }; @@ -84,7 +87,7 @@ static WindowDesc _template_create_window_desc( "template create window", // const char* ini_key 456, 100, // window size WC_CREATE_TEMPLATE, // window class - WC_TEMPLATEGUI_MAIN, // parent window class + WC_NONE, // parent window class WDF_CONSTRUCTION, // window flags _widgets, lengthof(_widgets) // widgets + num widgets ); @@ -104,12 +107,13 @@ static void TrainDepotMoveVehicle(const Vehicle *wagon, VehicleID sel, const Veh if (wagon == v) return; - CmdMoveRailVehicle(INVALID_TILE, DC_EXEC, (_ctrl_pressed ? 1:0)<<20 | (1<<21) | v->index, wagon == NULL ? INVALID_VEHICLE : wagon->index, 0); + DoCommandP(v->tile, v->index | (_ctrl_pressed ? 1 : 0) << 20 | 1 << 21, wagon == NULL ? INVALID_VEHICLE : wagon->index, CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_MOVE_VEHICLE), CcVirtualTrainWaggonsMoved); } class TemplateCreateWindow : public Window { private: Scrollbar *hscroll; + Scrollbar *vscroll; int line_height; Train* virtual_train; bool editMode; @@ -124,8 +128,9 @@ public: TemplateCreateWindow(WindowDesc* _wdesc, TemplateVehicle *to_edit, bool *notice, bool *windowOpen, int step_h) : Window(_wdesc) { this->line_height = step_h; - this->CreateNestedTree(_wdesc); - this->hscroll = this->GetScrollbar(TCW_SCROLLBAR_NEW_TMPL); + this->CreateNestedTree(_wdesc != NULL); + this->hscroll = this->GetScrollbar(TCW_SCROLLBAR_H_NEW_TMPL); + this->vscroll = this->GetScrollbar(TCW_SCROLLBAR_V_NEW_TMPL); this->FinishInitNested(VEH_TRAIN); /* a sprite */ this->GetWidget(TCW_SELL_TMPL)->widget_data = SPR_SELL_TRAIN; @@ -137,20 +142,25 @@ public: virtualTrainChangedNotice = false; this->editTemplate = to_edit; - if ( to_edit ) editMode = true; + if (to_edit) editMode = true; else editMode = false; this->sel = INVALID_VEHICLE; this->vehicle_over = INVALID_VEHICLE; - this->virtual_train = VirtualTrainFromTemplateVehicle(to_edit); + if (to_edit) { + DoCommandP(0, to_edit->index, 0, CMD_VIRTUAL_TRAIN_FROM_TEMPLATE_VEHICLE, CcSetVirtualTrain); + } this->resize.step_height = 1; } + ~TemplateCreateWindow() { - if ( virtual_train ) - delete virtual_train; + if (virtual_train != nullptr) { + DoCommandP(0, virtual_train->index, 0, CMD_DELETE_VIRTUAL_TRAIN); + virtual_train = nullptr; + } SetWindowClassesDirty(WC_TRAINS_LIST); @@ -160,19 +170,22 @@ public: } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void SetVirtualTrain(Train* const train) { - switch (widget) { - case TCW_MATRIX_NEW_TMPL: - size->height = 20; - break; + if (virtual_train != nullptr) { + DoCommandP(0, virtual_train->index, 0, CMD_DELETE_VIRTUAL_TRAIN); } + + virtual_train = train; } + virtual void OnResize() { - NWidgetCore *nwi = this->GetWidget(TCW_MATRIX_NEW_TMPL); - this->hscroll->SetCapacity(nwi->current_x); - nwi->widget_data = (this->hscroll->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START); + NWidgetCore *template_panel = this->GetWidget(TCW_NEW_TMPL_PANEL); + this->hscroll->SetCapacity(template_panel->current_x); + + NWidgetCore *info_panel = this->GetWidget(TCW_INFO_PANEL); + this->vscroll->SetCapacity(info_panel->current_y); } @@ -180,12 +193,13 @@ public: { virtualTrainChangedNotice = true; } + virtual void OnClick(Point pt, int widget, int click_count) { switch(widget) { - case TCW_MATRIX_NEW_TMPL: { - NWidgetBase *nwi = this->GetWidget(TCW_MATRIX_NEW_TMPL); - ClickedOnVehiclePanel(pt.x - nwi->pos_x-TRAIN_FRONT_SPACE, pt.y - nwi->pos_y); + case TCW_NEW_TMPL_PANEL: { + NWidgetBase *nwi = this->GetWidget(TCW_NEW_TMPL_PANEL); + ClickedOnVehiclePanel(pt.x - nwi->pos_x, pt.y - nwi->pos_y); break; } case TCW_NEW: { @@ -204,10 +218,14 @@ public: break; } case TCW_OK: { - TemplateVehicle *tv = NULL; - if ( editMode ) tv = DeleteTemplateVehicle(editTemplate); - editTemplate = TemplateVehicleFromVirtualTrain(virtual_train); - if ( tv ) *noticeParent = true; + uint32 templateIndex = (editTemplate != nullptr) ? editTemplate->index : INVALID_VEHICLE; + + if (virtual_train != nullptr) { + DoCommandP(0, templateIndex, virtual_train->index, CMD_REPLACE_TEMPLATE_VEHICLE); + virtual_train = nullptr; + } else if (templateIndex != INVALID_VEHICLE) { + DoCommandP(0, templateIndex, 0, CMD_DELETE_TEMPLATE_VEHICLE); + } delete this; break; } @@ -221,25 +239,30 @@ public: } } } + virtual bool OnVehicleSelect(const Vehicle *v) { // throw away the current virtual train - if ( virtual_train ) - delete this->virtual_train; + if (virtual_train != nullptr) { + DoCommandP(0, virtual_train->index, 0, CMD_DELETE_VIRTUAL_TRAIN); + virtual_train = nullptr; + } + // create a new one - this->virtual_train = CloneVirtualTrainFromTrain((const Train*)v); + DoCommandP(0, v->index, 0, CMD_VIRTUAL_TRAIN_FROM_TRAIN, CcSetVirtualTrain); this->ToggleWidgetLoweredState(TCW_CLONE); ResetObjectToPlace(); this->SetDirty(); return true; } + virtual void DrawWidget(const Rect &r, int widget) const { switch(widget) { - case TCW_MATRIX_NEW_TMPL: { + case TCW_NEW_TMPL_PANEL: { if ( this->virtual_train ) { - DrawTrainImage(virtual_train, r.left+TRAIN_FRONT_SPACE, r.right, r.top+2, this->sel, EIT_PURCHASE, this->hscroll->GetPosition(), this->vehicle_over); + DrawTrainImage(virtual_train, r.left+TRAIN_FRONT_SPACE, r.right-25, r.top+2, this->sel, EIT_PURCHASE, this->hscroll->GetPosition(), this->vehicle_over); SetDParam(0, CeilDiv(virtual_train->gcache.cached_total_length * 10, TILE_SIZE)); SetDParam(1, 1); DrawString(r.left, r.right, r.top, STR_TINY_BLACK_DECIMAL, TC_BLACK, SA_RIGHT); @@ -248,27 +271,36 @@ public: } case TCW_INFO_PANEL: { if ( this->virtual_train ) { + DrawPixelInfo tmp_dpi, *old_dpi; + + if (!FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left, r.bottom - r.top)) break; + + old_dpi = _cur_dpi; + _cur_dpi = &tmp_dpi; + /* Draw vehicle performance info */ const GroundVehicleCache *gcache = this->virtual_train->GetGroundVehicleCache(); SetDParam(2, this->virtual_train->GetDisplayMaxSpeed()); SetDParam(1, gcache->cached_power); SetDParam(0, gcache->cached_weight); SetDParam(3, gcache->cached_max_te / 1000); - DrawString(r.left+8, r.right, r.top+4, STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE); + DrawString(8, r.right, 4 - this->vscroll->GetPosition(), STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE); /* Draw cargo summary */ CargoArray cargo_caps; for ( const Train *tmp=this->virtual_train; tmp; tmp=tmp->Next() ) cargo_caps[tmp->cargo_type] += tmp->cargo_cap; - int y = r.top+24; + int y = 30 - this->vscroll->GetPosition(); for (CargoID i = 0; i < NUM_CARGO; ++i) { if ( cargo_caps[i] > 0 ) { SetDParam(0, i); SetDParam(1, cargo_caps[i]); SetDParam(2, _settings_game.vehicle.freight_trains); - DrawString(r.left+8, r.right, y, STR_TMPL_CARGO_SUMMARY, TC_WHITE, SA_LEFT); - y += this->line_height/2; + DrawString(8, r.right, y, STR_TMPL_CARGO_SUMMARY, TC_LIGHT_BLUE, SA_LEFT); + y += this->line_height/3; } } + + _cur_dpi = old_dpi; } break; } @@ -278,7 +310,7 @@ public: } virtual void OnTick() { - if ( virtualTrainChangedNotice ) { + if (virtualTrainChangedNotice) { this->SetDirty(); virtualTrainChangedNotice = false; } @@ -286,22 +318,20 @@ public: virtual void OnDragDrop(Point pt, int widget) { switch (widget) { - case TCW_MATRIX_NEW_TMPL: { + case TCW_NEW_TMPL_PANEL: { const Vehicle *v = NULL; - VehicleID sel; - if ( virtual_train ) sel = virtual_train->index; - else sel = INVALID_VEHICLE; + VehicleID sel = this->sel; + this->sel = INVALID_VEHICLE; this->SetDirty(); - NWidgetBase *nwi = this->GetWidget(TCW_MATRIX_NEW_TMPL); + NWidgetBase *nwi = this->GetWidget(TCW_NEW_TMPL_PANEL); GetDepotVehiclePtData gdvp = { NULL, NULL }; if (this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, &gdvp) == MODE_DRAG_VEHICLE && sel != INVALID_VEHICLE) { if (gdvp.wagon == NULL || gdvp.wagon->index != sel) { this->vehicle_over = INVALID_VEHICLE; TrainDepotMoveVehicle(gdvp.wagon, sel, gdvp.head); - virtual_train = virtual_train->First(); } } break; @@ -310,7 +340,14 @@ public: if (this->IsWidgetDisabled(widget)) return; if (this->sel == INVALID_VEHICLE) return; - virtual_train = DeleteVirtualTrain(virtual_train, Train::Get(this->sel)); + int sell_cmd = (_ctrl_pressed) ? 1 : 0; + + Train* train_to_delete = Train::Get(this->sel); + + if (virtual_train == train_to_delete) + virtual_train = (_ctrl_pressed) ? nullptr : virtual_train->GetNextUnit(); + + DoCommandP(0, this->sel | sell_cmd << 20 | 1 << 21, 0, GetCmdSellVeh(VEH_TRAIN)); this->sel = INVALID_VEHICLE; @@ -325,14 +362,15 @@ public: this->sel = INVALID_VEHICLE; this->SetDirty(); } + virtual void OnMouseDrag(Point pt, int widget) { if (this->sel == INVALID_VEHICLE) return; /* A rail vehicle is dragged.. */ - if (widget != TCW_MATRIX_NEW_TMPL) { // ..outside of the depot matrix. + if (widget != TCW_NEW_TMPL_PANEL) { // ..outside of the depot matrix. if (this->vehicle_over != INVALID_VEHICLE) { this->vehicle_over = INVALID_VEHICLE; - this->SetWidgetDirty(TCW_MATRIX_NEW_TMPL); + this->SetWidgetDirty(TCW_NEW_TMPL_PANEL); } return; } @@ -361,16 +399,33 @@ public: this->vehicle_over = new_vehicle_over; this->SetWidgetDirty(widget); } + virtual void OnPaint() { - uint max_width = 32; + uint min_width = 32; + uint min_height = 30; uint width = 0; - if ( virtual_train ) - for (Train *v = virtual_train; v != NULL; v = v->Next()) - width += v->GetDisplayImageWidth(); + uint height = 30; + CargoArray cargo_caps; - max_width = max(max_width, width); - this->hscroll->SetCount(max_width+25); + if (virtual_train != nullptr) { + for (Train *train = virtual_train; train != nullptr; train = train->Next()) { + width += train->GetDisplayImageWidth(); + cargo_caps[train->cargo_type] += train->cargo_cap; + } + + for (CargoID i = 0; i < NUM_CARGO; ++i) { + if ( cargo_caps[i] > 0 ) { + height += this->line_height/3; + } + } + } + + min_width = max(min_width, width); + this->hscroll->SetCount(min_width + 50); + + min_height = max(min_height, height); + this->vscroll->SetCount(min_height); this->DrawWidgets(); } @@ -388,11 +443,14 @@ public: uint count_width; uint header_width; - DepotGUIAction GetVehicleFromDepotWndPt(int x, int y, const Vehicle **veh, GetDepotVehiclePtData *d) const + + DepotGUIAction GetVehicleFromDepotWndPt(int x, int y, const Vehicle **veh, GetDepotVehiclePtData *d) const { - const NWidgetCore *matrix_widget = this->GetWidget(TCW_MATRIX_NEW_TMPL); + const NWidgetCore *matrix_widget = this->GetWidget(TCW_NEW_TMPL_PANEL); /* In case of RTL the widgets are swapped as a whole */ if (_current_text_dir == TD_RTL) x = matrix_widget->current_x - x; + + x -= TRAIN_FRONT_SPACE; uint xm = x; @@ -436,6 +494,7 @@ public: if (sel != INVALID_VEHICLE) { this->sel = INVALID_VEHICLE; + TrainDepotMoveVehicle(v, sel, gdvp.head); } else if (v != NULL) { int image = v->GetImage(_current_text_dir == TD_RTL ? DIR_E : DIR_W, EIT_PURCHASE); SetObjectToPlaceWnd(image, GetVehiclePalette(v), HT_DRAG, this); @@ -448,6 +507,10 @@ public: } } + void RearrangeVirtualTrain() + { + virtual_train = virtual_train->First(); + } }; void ShowTemplateCreateWindow(TemplateVehicle *to_edit, bool *noticeParent, bool *createWindowOpen, int step_h) @@ -456,4 +519,31 @@ void ShowTemplateCreateWindow(TemplateVehicle *to_edit, bool *noticeParent, bool new TemplateCreateWindow(&_template_create_window_desc, to_edit, noticeParent, createWindowOpen, step_h); } +void CcSetVirtualTrain(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Failed()) return; + Window* window = FindWindowById(WC_CREATE_TEMPLATE, 0); + if (window) { + Train* train = Train::From(Vehicle::Get(_new_vehicle_id)); + ((TemplateCreateWindow*)window)->SetVirtualTrain(train); + window->InvalidateData(); + } +} + +void CcVirtualTrainWaggonsMoved(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Failed()) return; + + Window* window = FindWindowById(WC_CREATE_TEMPLATE, 0); + if (window) { + ((TemplateCreateWindow*)window)->RearrangeVirtualTrain(); + window->InvalidateData(); + } +} + +void CcDeleteVirtualTrain(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + VehicleID virtual_train_id = p2; + DoCommandP(0, virtual_train_id, 0, CMD_DELETE_VIRTUAL_TRAIN); +} \ No newline at end of file diff --git a/src/tbtr_template_gui_create_virtualtrain.cpp b/src/tbtr_template_gui_create_virtualtrain.cpp index 23351671dd..63612ddb6e 100644 --- a/src/tbtr_template_gui_create_virtualtrain.cpp +++ b/src/tbtr_template_gui_create_virtualtrain.cpp @@ -650,8 +650,7 @@ struct BuildVirtualTrainWindow : Window { case WID_BV_BUILD: { EngineID sel_eng = this->sel_engine; if (sel_eng != INVALID_ENGINE) { - Train *tmp = CmdBuildVirtualRailVehicle(sel_eng); - if (tmp) AddVirtualEngine(tmp); + DoCommandP(0, sel_engine, 0, CMD_BUILD_VIRTUAL_RAIL_VEHICLE, CcAddVirtualEngine); } break; } @@ -667,12 +666,7 @@ struct BuildVirtualTrainWindow : Window { { if (!gui_scope) return; /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */ - if (this->vehicle_type == VEH_ROAD && - _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL && - this->sort_criteria > 7) { - this->sort_criteria = 0; - _last_sort_criteria[VEH_ROAD] = 0; - } + this->eng_list.ForceRebuild(); } @@ -796,18 +790,29 @@ struct BuildVirtualTrainWindow : Window { void AddVirtualEngine(Train *toadd) { - if ( !*virtual_train ) { + if (*virtual_train == NULL) { *virtual_train = toadd; - } - else { + } else { VehicleID target = (*(this->virtual_train))->GetLastUnit()->index; - CommandCost movec; - movec = CmdMoveRailVehicle(INVALID_TILE, DC_EXEC, (1<<21) | toadd->index, target, 0); + + DoCommandP(0, (1<<21) | toadd->index, target, CMD_MOVE_RAIL_VEHICLE); } *noticeParent = true; } }; +void CcAddVirtualEngine(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Failed()) return; + + Window* window = FindWindowById(WC_BUILD_VIRTUAL_TRAIN, 0); + if (window) { + Train* train = Train::From(Vehicle::Get(_new_vehicle_id)); + ((BuildVirtualTrainWindow*)window)->AddVirtualEngine(train); + window->InvalidateData(); + } +} + static WindowDesc _build_vehicle_desc( WDP_AUTO, // window position "template create virtual train",// const char* ini_key diff --git a/src/tbtr_template_gui_main.cpp b/src/tbtr_template_gui_main.cpp index 5bd39c517a..82b6c18029 100644 --- a/src/tbtr_template_gui_main.cpp +++ b/src/tbtr_template_gui_main.cpp @@ -24,6 +24,7 @@ #include "settings_func.h" #include "core/geometry_func.hpp" #include "rail_gui.h" +#include "network/network.h" #include "table/sprites.h" #include "table/strings.h" @@ -60,6 +61,7 @@ enum TemplateReplaceWindowWidgets { TRW_WIDGET_INSET_TEMPLATES, TRW_WIDGET_BOTTOM_MATRIX, + TRW_WIDGET_MIDDLE_SCROLLBAR, TRW_WIDGET_BOTTOM_SCROLLBAR, TRW_WIDGET_TMPL_INFO_INSET, @@ -76,7 +78,7 @@ enum TemplateReplaceWindowWidgets { TRW_WIDGET_TMPL_BUTTONS_EDIT, TRW_WIDGET_TMPL_BUTTONS_CLONE, TRW_WIDGET_TMPL_BUTTONS_DELETE, - TRW_WIDGET_TMPL_BUTTONS_RPLALL, + //TRW_WIDGET_TMPL_BUTTONS_RPLALL, TRW_WIDGET_TMPL_BUTTON_FLUFF, TRW_WIDGET_TMPL_BUTTONS_EDIT_RIGHTPANEL, @@ -84,7 +86,7 @@ enum TemplateReplaceWindowWidgets { TRW_WIDGET_TITLE_INFO_TEMPLATE, TRW_WIDGET_INFO_GROUP, - TRW_WIDGET_INFO_TEMPLATE, + TRW_WIDGET_INFO_TEMPLATE, TRW_WIDGET_TMPL_BUTTONS_SPACER, @@ -103,11 +105,12 @@ static const NWidgetPart _widgets[] = { NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, TRW_CAPTION), SetDataTip(STR_TMPL_RPL_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), //Top Matrix NWidget(NWID_VERTICAL), - NWidget(WWT_INSET, COLOUR_GREY, TRW_WIDGET_INSET_GROUPS), SetMinimalSize(216,12), SetDataTip(STR_TMPL_MAINGUI_DEFINEDGROUPS, STR_TMPL_MAINGUI_DEFINEDGROUPS), SetResize(1, 0), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, TRW_WIDGET_INSET_GROUPS), SetMinimalTextLines(1, WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_GREY, TRW_WIDGET_TOP_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetDataTip(0x1, STR_REPLACE_HELP_LEFT_ARRAY), SetResize(1, 0), SetScrollbar(TRW_WIDGET_TOP_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, TRW_WIDGET_TOP_SCROLLBAR), @@ -115,16 +118,19 @@ static const NWidgetPart _widgets[] = { EndContainer(), // Template Display NWidget(NWID_VERTICAL), - NWidget(WWT_INSET, COLOUR_GREY, TRW_WIDGET_INSET_TEMPLATES), SetMinimalSize(216,12), SetDataTip(STR_TMPL_AVAILABLE_TEMPLATES, STR_TMPL_AVAILABLE_TEMPLATES), SetResize(1, 0), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, TRW_WIDGET_INSET_TEMPLATES), SetMinimalTextLines(1, WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), - NWidget(WWT_MATRIX, COLOUR_GREY, TRW_WIDGET_BOTTOM_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetDataTip(0x1, STR_REPLACE_HELP_RIGHT_ARRAY), SetResize(1, 1), SetScrollbar(TRW_WIDGET_BOTTOM_SCROLLBAR), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, TRW_WIDGET_BOTTOM_SCROLLBAR), + NWidget(WWT_MATRIX, COLOUR_GREY, TRW_WIDGET_BOTTOM_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetDataTip(0x1, STR_REPLACE_HELP_RIGHT_ARRAY), SetResize(1, 1), SetScrollbar(TRW_WIDGET_MIDDLE_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, TRW_WIDGET_MIDDLE_SCROLLBAR), EndContainer(), EndContainer(), // Info Area NWidget(NWID_VERTICAL), - NWidget(WWT_INSET, COLOUR_GREY, TRW_WIDGET_TMPL_INFO_INSET), SetMinimalSize(216,12), SetResize(1,0), SetDataTip(STR_TMPL_AVAILABLE_TEMPLATES, STR_TMPL_AVAILABLE_TEMPLATES), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, TRW_WIDGET_TMPL_INFO_PANEL), SetMinimalSize(216,50), SetResize(1,0), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, TRW_WIDGET_TMPL_INFO_INSET), SetMinimalTextLines(1, WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM), SetResize(1,0), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_GREY, TRW_WIDGET_TMPL_INFO_PANEL), SetMinimalSize(216,120), SetResize(1,0), SetScrollbar(TRW_WIDGET_BOTTOM_SCROLLBAR), EndContainer(), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, TRW_WIDGET_BOTTOM_SCROLLBAR), + EndContainer(), EndContainer(), // Control Area NWidget(NWID_VERTICAL), @@ -139,11 +145,10 @@ static const NWidgetPart _widgets[] = { EndContainer(), // Edit buttons NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_DEFINE), SetMinimalSize(75,12), SetResize(0,0), SetDataTip(STR_TMPL_DEFINE_TEMPLATE, STR_REPLACE_ENGINE_WAGON_SELECT_HELP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_EDIT), SetMinimalSize(75,12), SetResize(0,0), SetDataTip(STR_TMPL_EDIT_TEMPLATE, STR_REPLACE_ENGINE_WAGON_SELECT_HELP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_CLONE), SetMinimalSize(75,12), SetResize(0,0), SetDataTip(STR_TMPL_CREATE_CLONE_VEH, STR_REPLACE_ENGINE_WAGON_SELECT_HELP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_DELETE), SetMinimalSize(75,12), SetResize(0,0), SetDataTip(STR_TMPL_DELETE_TEMPLATE, STR_REPLACE_ENGINE_WAGON_SELECT_HELP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_RPLALL), SetMinimalSize(150,12), SetResize(0,0), SetDataTip(STR_TMPL_RPL_ALL_TMPL, STR_REPLACE_ENGINE_WAGON_SELECT_HELP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_DEFINE), SetMinimalSize(75,12), SetResize(0,0), SetDataTip(STR_TMPL_DEFINE_TEMPLATE, STR_TMPL_DEFINE_TEMPLATE), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_EDIT), SetMinimalSize(75,12), SetResize(0,0), SetDataTip(STR_TMPL_EDIT_TEMPLATE, STR_TMPL_EDIT_TEMPLATE), + NWidget(WWT_TEXTBTN, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_CLONE), SetMinimalSize(75,12), SetResize(0,0), SetDataTip(STR_TMPL_CREATE_CLONE_VEH, STR_TMPL_CREATE_CLONE_VEH), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_DELETE), SetMinimalSize(75,12), SetResize(0,0), SetDataTip(STR_TMPL_DELETE_TEMPLATE, STR_TMPL_DELETE_TEMPLATE), NWidget(WWT_PANEL, COLOUR_GREY, TRW_WIDGET_TMPL_BUTTONS_EDIT_RIGHTPANEL), SetMinimalSize(50,12), SetResize(1,0), EndContainer(), EndContainer(), EndContainer(), @@ -174,12 +179,14 @@ private: GUIGroupList groups; ///< List of groups byte unitnumber_digits; + SmallVector indents; ///< Indentation levels + short line_height; short matrixContentLeftMargin; int details_height; ///< Minimal needed height of the details panels (found so far). RailType sel_railtype; ///< Type of rail tracks selected. - Scrollbar *vscroll[2]; + Scrollbar *vscroll[3]; // listing/sorting continued GUITemplateList templates; GUITemplateList::SortFunction **template_sorter_funcs; @@ -204,20 +211,17 @@ public: this->line_height = step_h; - this->CreateNestedTree(wdesc); + this->CreateNestedTree(wdesc != NULL); this->vscroll[0] = this->GetScrollbar(TRW_WIDGET_TOP_SCROLLBAR); - this->vscroll[1] = this->GetScrollbar(TRW_WIDGET_BOTTOM_SCROLLBAR); - this->vscroll[0]->SetStepSize(step_h / 2); - this->vscroll[1]->SetStepSize(step_h); + this->vscroll[1] = this->GetScrollbar(TRW_WIDGET_MIDDLE_SCROLLBAR); + this->vscroll[2] = this->GetScrollbar(TRW_WIDGET_BOTTOM_SCROLLBAR); this->FinishInitNested(VEH_TRAIN); this->owner = _local_company; this->groups.ForceRebuild(); this->groups.NeedResort(); - this->BuildGroupList(_local_company); - this->groups.Sort(&GroupNameSorter); - + this->BuildGroupList(_local_company); this->matrixContentLeftMargin = 40; this->selected_template_index = -1; @@ -286,6 +290,18 @@ public: DrawTemplateInfo(this->line_height, r); break; } + case TRW_WIDGET_INSET_GROUPS: { + DrawString(r.left + 2, r.right - 2, r.top + 2, STR_TMPL_MAINGUI_DEFINEDGROUPS); + break; + } + case TRW_WIDGET_INSET_TEMPLATES: { + DrawString(r.left + 2, r.right - 2, r.top + 2, STR_TMPL_AVAILABLE_TEMPLATES); + break; + } + case TRW_WIDGET_TMPL_INFO_INSET: { + DrawString(r.left + 2, r.right - 2, r.top + 2, STR_TMPL_TEMPLATE_INFO); + break; + } } } @@ -294,7 +310,6 @@ public: BuildTemplateGuiList(&this->templates, this->vscroll[1], this->owner, this->sel_railtype); this->BuildGroupList(_local_company); - this->groups.Sort(&GroupNameSorter); if ( templateNotice ) { BuildTemplateGuiList(&this->templates, vscroll[1], _local_company, this->sel_railtype); @@ -308,6 +323,34 @@ public: /* Show the selected railtype in the pulldown menu */ this->GetWidget(TRW_WIDGET_TRAIN_RAILTYPE_DROPDOWN)->widget_data = GetRailTypeInfo(sel_railtype)->strings.replace_text; + if ((this->selected_template_index < 0) || (this->selected_template_index >= (short)this->templates.Length())) { + this->vscroll[2]->SetCount(24); + } else { + const TemplateVehicle *tmp = this->templates[this->selected_template_index]; + uint min_height = 30; + uint height = 30; + CargoArray cargo_caps; + short count_columns = 0; + short max_columns = 2; + + for ( ; tmp; tmp=tmp->Next()) { + cargo_caps[tmp->cargo_type] += tmp->cargo_cap; + } + + for (CargoID i = 0; i < NUM_CARGO; ++i) { + if ( cargo_caps[i] > 0 ) { + if (count_columns % max_columns == 0) { + height += this->line_height/3; + } + + ++count_columns; + } + } + + min_height = max(min_height, height); + this->vscroll[2]->SetCount(min_height); + } + this->DrawWidgets(); } @@ -317,31 +360,35 @@ public: switch (widget) { case TRW_WIDGET_TMPL_BUTTONS_CONFIGTMPL_REUSE: { - if ( this->selected_template_index >= 0 ) { - TemplateVehicle *sel = TemplateVehicle::Get(((this->templates)[selected_template_index])->index); - sel->ToggleReuseDepotVehicles(); + if ((this->selected_template_index >= 0) && (this->selected_template_index < (short)this->templates.Length())) { + uint32 template_index = ((this->templates)[selected_template_index])->index; + + DoCommandP(0, template_index, 0, CMD_TOGGLE_REUSE_DEPOT_VEHICLES, NULL); } break; } case TRW_WIDGET_TMPL_BUTTONS_CONFIGTMPL_KEEP: { - if ( this->selected_template_index >= 0 ) { - TemplateVehicle *sel = TemplateVehicle::Get(((this->templates)[selected_template_index])->index); - sel->ToggleKeepRemainingVehicles(); + if ((this->selected_template_index >= 0) && (this->selected_template_index < (short)this->templates.Length())) { + uint32 template_index = ((this->templates)[selected_template_index])->index; + + DoCommandP(0, template_index, 0, CMD_TOGGLE_KEEP_REMAINING_VEHICLES, NULL); } break; } case TRW_WIDGET_TMPL_BUTTONS_CONFIGTMPL_REFIT: { - if ( this->selected_template_index >= 0 ) { - TemplateVehicle *sel = TemplateVehicle::Get(((this->templates)[selected_template_index])->index); - sel->ToggleRefitAsTemplate(); + if ((this->selected_template_index >= 0) && (this->selected_template_index < (short)this->templates.Length())) { + uint32 template_index = ((this->templates)[selected_template_index])->index; + + DoCommandP(0, template_index, 0, CMD_TOGGLE_REFIT_AS_TEMPLATE, NULL); } break; } - case TRW_WIDGET_TMPL_BUTTONS_DEFINE: + case TRW_WIDGET_TMPL_BUTTONS_DEFINE: { ShowTemplateCreateWindow(0, &templateNotice, &editInProgress, this->line_height); break; + } case TRW_WIDGET_TMPL_BUTTONS_EDIT: { - if ( this->selected_template_index >= 0 ) { + if ((this->selected_template_index >= 0) && (this->selected_template_index < (short)this->templates.Length())) { editInProgress = true; TemplateVehicle *sel = TemplateVehicle::Get(((this->templates)[selected_template_index])->index); ShowTemplateCreateWindow(sel, &templateNotice, &editInProgress, this->line_height); @@ -361,61 +408,58 @@ public: break; } case TRW_WIDGET_TMPL_BUTTONS_DELETE: - if ( selected_template_index >= 0 && !editInProgress ) { - // identify template to delete - TemplateVehicle *del = TemplateVehicle::Get(((this->templates)[selected_template_index])->index); - // remove a corresponding template replacement if existing - TemplateReplacement *tr = GetTemplateReplacementByTemplateID(del->index); - if ( tr ) { - delete tr; + if ((this->selected_template_index >= 0) && (this->selected_template_index < (short)this->templates.Length()) && !editInProgress) { + + uint32 template_index = ((this->templates)[selected_template_index])->index; + + bool succeeded = DoCommandP(0, template_index, 0, CMD_DELETE_TEMPLATE_VEHICLE, NULL); + + if (succeeded) { + BuildTemplateGuiList(&this->templates, this->vscroll[1], this->owner, this->sel_railtype); + selected_template_index = -1; } - delete del; - BuildTemplateGuiList(&this->templates, this->vscroll[1], this->owner, this->sel_railtype); - selected_template_index = -1; } break; - case TRW_WIDGET_TMPL_BUTTONS_RPLALL: { - ShowTemplateReplaceAllGui(); - break; - } case TRW_WIDGET_TRAIN_RAILTYPE_DROPDOWN: // Railtype selection dropdown menu ShowDropDownList(this, GetRailTypeDropDownList(true), sel_railtype, TRW_WIDGET_TRAIN_RAILTYPE_DROPDOWN); break; case TRW_WIDGET_TOP_MATRIX: { - uint16 newindex = (uint16)((pt.y - this->nested_array[TRW_WIDGET_TOP_MATRIX]->pos_y) / (this->line_height/2) ) + this->vscroll[0]->GetPosition(); + uint16 newindex = (uint16)((pt.y - this->nested_array[TRW_WIDGET_TOP_MATRIX]->pos_y) / (this->line_height/2) ) + this->vscroll[0]->GetPosition(); if ( newindex == this->selected_group_index || newindex >= this->groups.Length() ) { this->selected_group_index = -1; } - else if ( newindex < this->groups.Length() ) { + else if ((newindex >= 0) && (newindex < this->groups.Length())) { this->selected_group_index = newindex; } break; } case TRW_WIDGET_BOTTOM_MATRIX: { - uint16 newindex = (uint16)((pt.y - this->nested_array[TRW_WIDGET_BOTTOM_MATRIX]->pos_y) / this->line_height) + this->vscroll[1]->GetPosition(); + uint16 newindex = (uint16)((pt.y - this->nested_array[TRW_WIDGET_BOTTOM_MATRIX]->pos_y) / this->line_height) + this->vscroll[1]->GetPosition(); if ( newindex == this->selected_template_index || newindex >= templates.Length() ) { this->selected_template_index = -1; } - else if ( newindex < templates.Length() ) { + else if ((newindex >= 0) && (newindex < templates.Length())) { this->selected_template_index = newindex; } break; } case TRW_WIDGET_START: { - if ( this->selected_template_index >= 0 && this->selected_group_index >= 0) { + if ((this->selected_template_index >= 0) && (this->selected_template_index < (short)this->templates.Length()) && + (this->selected_group_index >= 0) && (this->selected_group_index < (short)this->groups.Length())) { uint32 tv_index = ((this->templates)[selected_template_index])->index; int current_group_index = (this->groups)[this->selected_group_index]->index; - IssueTemplateReplacement(current_group_index, tv_index); + + DoCommandP(0, current_group_index, tv_index, CMD_ISSUE_TEMPLATE_REPLACEMENT, NULL); } break; } case TRW_WIDGET_STOP: - if ( this->selected_group_index == -1 ) + if ((this->selected_group_index < 0) || (this->selected_group_index >= (short)this->groups.Length())) return; + int current_group_index = (this->groups)[this->selected_group_index]->index; - TemplateReplacement *tr = GetTemplateReplacementByGroupID(current_group_index); - if ( tr ) - delete tr; + + DoCommandP(0, current_group_index, 0, CMD_DELETE_TEMPLATE_REPLACEMENT, NULL); break; } this->SetDirty(); @@ -423,9 +467,9 @@ public: virtual bool OnVehicleSelect(const Vehicle *v) { - // create a new template from the clicked vehicle - TemplateVehicle *tv = CloneTemplateVehicleFromTrain((const Train*)v); - if ( !tv ) return false; + bool succeeded = DoCommandP(0, v->index, 0, CMD_CLONE_TEMPLATE_VEHICLE_FROM_TRAIN, NULL); + + if (!succeeded) return false; BuildTemplateGuiList(&this->templates, vscroll[1], _local_company, this->sel_railtype); this->ToggleWidgetLoweredState(TRW_WIDGET_TMPL_BUTTONS_CLONE); @@ -457,6 +501,9 @@ public: NWidgetCore *nwi2 = this->GetWidget(TRW_WIDGET_BOTTOM_MATRIX); this->vscroll[1]->SetCapacityFromWidget(this, TRW_WIDGET_BOTTOM_MATRIX); nwi2->widget_data = (this->vscroll[1]->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START); + /* Info panel */ + NWidgetCore *nwi3 = this->GetWidget(TRW_WIDGET_TMPL_INFO_PANEL); + this->vscroll[2]->SetCapacity(nwi3->current_y); } virtual void OnTick() @@ -489,6 +536,17 @@ public: return -1; } + void AddParents(GUIGroupList *source, GroupID parent, int indent) + { + for (const Group **g = source->Begin(); g != source->End(); g++) { + if ((*g)->parent == parent) { + *this->groups.Append() = *g; + *this->indents.Append() = indent; + AddParents(source, (*g)->index, indent + 1); + } + } + } + /** Sort the groups by their name */ static int CDECL GroupNameSorter(const Group * const *a, const Group * const *b) { @@ -514,18 +572,25 @@ public: void BuildGroupList(Owner owner) { - if (!this->groups.NeedRebuild()) { - return; - } + if (!this->groups.NeedRebuild()) return; + this->groups.Clear(); + this->indents.Clear(); + + GUIGroupList list; const Group *g; FOR_ALL_GROUPS(g) { - if (g->owner == owner ) { - *this->groups.Append() = g; + if (g->owner == owner && g->vehicle_type == VEH_TRAIN) { + *list.Append() = g; } } + list.ForceResort(); + list.Sort(&GroupNameSorter); + + AddParents(&list, INVALID_GROUP, 0); + this->groups.Compact(); this->groups.RebuildDone(); this->vscroll[0]->SetCount(groups.Length()); @@ -550,7 +615,7 @@ public: SetDParam(0, g_id); StringID str = STR_GROUP_NAME; - DrawString(left+30, right, y+2, str, TC_BLACK); + DrawString(left+30+ this->indents[i] * 10, right, y+2, str, TC_BLACK); /* Draw the template in use for this group, if there is one */ short template_in_use = FindTemplateIndexForGroup(g_id); @@ -621,24 +686,24 @@ public: /* Index of current template vehicle in the list of all templates for its company */ SetDParam(0, i); - DrawString(left+5, left+25, y + line_height/2, STR_BLACK_INT, TC_BLACK, SA_RIGHT); + DrawString(left+5, left+25, y + 2, STR_BLACK_INT, TC_BLACK, SA_RIGHT); /* Draw whether the current template is in use by any group */ if ( v->NumGroupsUsingTemplate() > 0 ) { - DrawString(left+200, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMP_TEMPLATE_IN_USE, TC_GREEN, SA_LEFT); + DrawString(left+35, right, y + line_height - FONT_HEIGHT_SMALL * 2 - 4 - WD_FRAMERECT_BOTTOM - 2, STR_TMP_TEMPLATE_IN_USE, TC_GREEN, SA_LEFT); } /* Draw information about template configuration settings */ TextColour color; if ( v->IsSetReuseDepotVehicles() ) color = TC_LIGHT_BLUE; else color = TC_GREY; - DrawString(left+200, right, y+2, STR_TMPL_CONFIG_USEDEPOT, color, SA_LEFT); + DrawString(left+300, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_CONFIG_USEDEPOT, color, SA_LEFT); if ( v->IsSetKeepRemainingVehicles() ) color = TC_LIGHT_BLUE; else color = TC_GREY; - DrawString(left+275, right, y+2, STR_TMPL_CONFIG_KEEPREMAINDERS, color, SA_LEFT); + DrawString(left+400, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_CONFIG_KEEPREMAINDERS, color, SA_LEFT); if ( v->IsSetRefitAsTemplate() ) color = TC_LIGHT_BLUE; else color = TC_GREY; - DrawString(left+350, right, y+2, STR_TMPL_CONFIG_REFIT, color, SA_LEFT); + DrawString(left+500, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_CONFIG_REFIT, color, SA_LEFT); y += line_height; } @@ -646,9 +711,17 @@ public: void DrawTemplateInfo(int line_height, const Rect &r) const { - if ( this->selected_template_index == -1 || (short)this->templates.Length() <= this->selected_template_index ) + if ((this->selected_template_index < 0) || (this->selected_template_index >= (short)this->templates.Length())) return; + DrawPixelInfo tmp_dpi, *old_dpi; + + if (!FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left, r.bottom - r.top)) + return; + + old_dpi = _cur_dpi; + _cur_dpi = &tmp_dpi; + const TemplateVehicle *tmp = this->templates[this->selected_template_index]; /* Draw vehicle performance info */ @@ -656,32 +729,34 @@ public: SetDParam(1, tmp->power); SetDParam(0, tmp->weight); SetDParam(3, tmp->max_te); - DrawString(r.left+8, r.right, r.top+4, STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE); + DrawString(8, r.right, 4 - this->vscroll[2]->GetPosition(), STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE); /* Draw cargo summary */ - short top = r.top + 24; - short left = r.left + 8; - short count_rows = 0; - short max_rows = 2; + short top = 30 - this->vscroll[2]->GetPosition(); + short left = 8; + short count_columns = 0; + short max_columns = 2; CargoArray cargo_caps; for ( ; tmp; tmp=tmp->Next() ) cargo_caps[tmp->cargo_type] += tmp->cargo_cap; - int y = top; + int x = left; for (CargoID i = 0; i < NUM_CARGO; ++i) { if ( cargo_caps[i] > 0 ) { - count_rows++; + count_columns++; SetDParam(0, i); SetDParam(1, cargo_caps[i]); SetDParam(2, _settings_game.vehicle.freight_trains); - DrawString(left, r.right, y, FreightWagonMult(i) > 1 ? STR_TMPL_CARGO_SUMMARY_MULTI : STR_TMPL_CARGO_SUMMARY, TC_WHITE, SA_LEFT); - y += this->line_height/2; - if ( count_rows % max_rows == 0 ) { - y = top; - left += 150; + DrawString(x, r.right, top, FreightWagonMult(i) > 1 ? STR_TMPL_CARGO_SUMMARY_MULTI : STR_TMPL_CARGO_SUMMARY, TC_LIGHT_BLUE, SA_LEFT); + x += 250; + if ( count_columns % max_columns == 0 ) { + x = left; + top += this->line_height/3; } } } + + _cur_dpi = old_dpi; } }; diff --git a/src/tbtr_template_gui_replaceall.cpp b/src/tbtr_template_gui_replaceall.cpp index 51b8cea4db..36d4396582 100644 --- a/src/tbtr_template_gui_replaceall.cpp +++ b/src/tbtr_template_gui_replaceall.cpp @@ -145,8 +145,7 @@ private: public: TemplateReplacementReplaceAllWindow(WindowDesc *wdesc) : Window(wdesc) { - - this->CreateNestedTree(wdesc); + this->CreateNestedTree(wdesc != nullptr); this->vscroll_tl = this->GetScrollbar(RPLALL_GUI_SCROLL_TL); this->vscroll_tr = this->GetScrollbar(RPLALL_GUI_SCROLL_TR); @@ -193,7 +192,7 @@ public: virtual void OnPaint() { - this->GetWidget(RPLALL_GUI_PANEL_BUTTONFLUFF_3)->colour = _company_colours[_local_company]; + this->GetWidget(RPLALL_GUI_PANEL_BUTTONFLUFF_3)->colour = _company_colours[_local_company]; this->DrawWidgets(); } diff --git a/src/tbtr_template_vehicle.h b/src/tbtr_template_vehicle.h index 82aeecfcda..1773cddc2d 100644 --- a/src/tbtr_template_vehicle.h +++ b/src/tbtr_template_vehicle.h @@ -27,8 +27,6 @@ struct TemplateVehicle; struct TemplateReplacement; -CommandCost CmdBuildTemplateVehicle(uint i, DoCommandFlag flags, uint p1, uint p2, char const* text); -CommandCost CmdTemplateReplaceVehicle(uint i, DoCommandFlag flags, uint p1, uint p2, char const* text); typedef uint16 TemplateID; @@ -171,11 +169,11 @@ struct TemplateReplacement : TemplateReplacementPool::PoolItem<&_template_replac inline GroupID Group() { return this->group; } inline GroupID Template() { return this->sel_template; } - inline void SetGroup(GroupID gid) { this->group = gid; } - inline void SetTemplate(TemplateID tid) { this->sel_template = tid; } + inline void SetGroup(GroupID gid) { this->group = gid; } + inline void SetTemplate(TemplateID tid) { this->sel_template = tid; } - inline TemplateID GetTemplateVehicleID() { return sel_template; } - inline const TemplateVehicle* GetTemplateVehicle() { + inline TemplateID GetTemplateVehicleID() { return sel_template; } + inline const TemplateVehicle* GetTemplateVehicle() { const TemplateVehicle *tv; FOR_ALL_TEMPLATES(tv) { if ( tv->index == this->sel_template ) diff --git a/src/tbtr_template_vehicle_func.cpp b/src/tbtr_template_vehicle_func.cpp index 69f847a674..55cfdc01c0 100644 --- a/src/tbtr_template_vehicle_func.cpp +++ b/src/tbtr_template_vehicle_func.cpp @@ -142,52 +142,6 @@ inline void SetupTemplateVehicleFromVirtual(TemplateVehicle *tmp, TemplateVehicl tmp->image_width = virt->GetDisplayImageWidth(p); } -// create a new virtual train as clone of a real train -Train* CloneVirtualTrainFromTrain(const Train *clicked) -{ - if ( !clicked ) return 0; - CommandCost c; - Train *tmp, *head, *tail; - - head = CmdBuildVirtualRailVehicle(clicked->engine_type); - if ( !head ) return 0; - - tail = head; - clicked = clicked->GetNextUnit(); - while ( clicked ) { - tmp = CmdBuildVirtualRailVehicle(clicked->engine_type); - if ( tmp ) { - tmp->cargo_type = clicked->cargo_type; - tmp->cargo_subtype = clicked->cargo_subtype; - CmdMoveRailVehicle(0, DC_EXEC, (1<<21) | tmp->index, tail->index, 0); - tail = tmp; - } - clicked = clicked->GetNextUnit(); - } - return head; -} -TemplateVehicle* CloneTemplateVehicleFromTrain(const Train *t) -{ - Train *clicked = Train::Get(t->index); - if ( !clicked ) - return 0; - - Train *init_clicked = clicked; - - int len = CountVehiclesInChain(clicked); - if ( !TemplateVehicle::CanAllocateItem(len) ) - return 0; - - TemplateVehicle *tmp, *prev=0; - for ( ; clicked; clicked=clicked->Next() ) { - tmp = new TemplateVehicle(clicked->engine_type); - SetupTemplateVehicleFromVirtual(tmp, prev, clicked); - prev = tmp; - } - - tmp->First()->SetRealLength(CeilDiv(init_clicked->gcache.cached_total_length * 10, TILE_SIZE)); - return tmp->First(); -} // create a full TemplateVehicle based train according to a virtual train TemplateVehicle* TemplateVehicleFromVirtualTrain(Train *virt) { @@ -211,32 +165,6 @@ TemplateVehicle* TemplateVehicleFromVirtualTrain(Train *virt) return tmp->First(); } -// attempt to buy a train after a given template vehicle -// this might fail if the template e.g. deprecated and contains engines that are not sold anymore -Train* VirtualTrainFromTemplateVehicle(TemplateVehicle *tv) -{ - if ( !tv ) return 0; - CommandCost c; - Train *tmp, *head, *tail; - - head = CmdBuildVirtualRailVehicle(tv->engine_type); - if ( !head ) return 0; - - tail = head; - tv = tv->GetNextUnit(); - while ( tv ) { - tmp = CmdBuildVirtualRailVehicle(tv->engine_type); - if ( tmp ) { - tmp->cargo_type = tv->cargo_type; - tmp->cargo_subtype = tv->cargo_subtype; - CmdMoveRailVehicle(INVALID_TILE, DC_EXEC, (1<<21) | tmp->index, tail->index, 0); - tail = tmp; - } - tv = tv->GetNextUnit(); - } - return head; -} - // return last in a chain (really last, so even a singular articulated part of a vehicle if the last one is artic) inline TemplateVehicle* Last(TemplateVehicle *chain) { if ( !chain ) return 0; @@ -337,7 +265,7 @@ Train* DepotContainsEngine(TileIndex tile, EngineID eid, Train *not_in=0) { Train *t; FOR_ALL_TRAINS(t) { // conditions: v is stopped in the given depot, has the right engine and if 'not_in' is given v must not be contained within 'not_in' - // if 'not_in' is NULL, no check is needed + // if 'not_in' is NULL, no check is needed if ( t->tile==tile // If the veh belongs to a chain, wagons will not return true on IsStoppedInDepot(), only primary vehicles will // in case of t not a primary veh, we demand it to be a free wagon to consider it for replacement @@ -366,8 +294,9 @@ void CopyStatus(Train *from, Train *to) { } void NeutralizeStatus(Train *t) { DoCommand(t->tile, DEFAULT_GROUP, t->index, DC_EXEC, CMD_ADD_VEHICLE_GROUP); - - t->name = 0; + DoCommand(0, t->index | CO_UNSHARE << 30, 0, DC_EXEC, CMD_CLONE_ORDER); + DoCommand(0, t->index, FreeUnitIDGenerator(VEH_TRAIN, t->owner).NextID(), DC_EXEC, CMD_SET_VEHICLE_UNIT_NUMBER); + DoCommand(0, t->index, 0, DC_EXEC, CMD_RENAME_VEHICLE, NULL); } bool TrainMatchesTemplate(const Train *t, TemplateVehicle *tv) { while ( t && tv ) { @@ -440,7 +369,7 @@ int countOccurrencesInDepot(TileIndex tile, EngineID eid, Train *not_in=0) { Vehicle *v; FOR_ALL_VEHICLES(v) { // conditions: v is stopped in the given depot, has the right engine and if 'not_in' is given v must not be contained within 'not_in' - // if 'not_in' is NULL, no check is needed + // if 'not_in' is NULL, no check is needed if ( v->tile==tile && v->IsStoppedInDepot() && v->engine_type==eid && (not_in==0 || ChainContainsVehicle(not_in, (Train*)v)==0)) count++; @@ -494,13 +423,13 @@ int NumTrainsNeedTemplateReplacement(GroupID g_id, TemplateVehicle *tv) return count; } // refit each vehicle in t as is in tv, assume t and tv contain the same types of vehicles -static void RefitTrainFromTemplate(Train *t, TemplateVehicle *tv) +void CmdRefitTrainFromTemplate(Train *t, TemplateVehicle *tv, DoCommandFlag flags) { while ( t && tv ) { // refit t as tv uint32 cb = GetCmdRefitVeh(t); - DoCommandP(t->tile, t->index, tv->cargo_type | tv->cargo_subtype << 8 | 1 << 16 , cb); + DoCommand(t->tile, t->index, tv->cargo_type | tv->cargo_subtype << 8 | 1 << 16 | (1 << 5), flags, cb); // next t = t->GetNextUnit(); @@ -546,7 +475,7 @@ void TransferCargoForTrain(Train *old_veh, Train *new_head) { // calculate the free space for new cargo on the current vehicle uint curCap = tmp->cargo_cap - tmp->cargo.TotalCount(); - uint moveAmount = std::min(remainingAmount, curCap); + uint moveAmount = min(remainingAmount, curCap); // move (parts of) the old vehicle's cargo onto the current vehicle of the new chain if (moveAmount > 0) { @@ -562,184 +491,7 @@ void TransferCargoForTrain(Train *old_veh, Train *new_head) //if (src->cargo_cap < src->cargo.TotalCount()) src->cargo.Truncate(src->cargo.TotalCount() - src->cargo_cap); /* Update train weight etc., the old vehicle will be sold anyway */ - new_head->ConsistChanged(ConsistChangeFlags::CCF_LOADUNLOAD); -} - -// TODO: fit signature to regular cmd-structure -// do something with move_cost, it is not used right now -// if exec==DC_EXEC, test first and execute if sucessful -CommandCost CmdTemplateReplaceVehicle(Train *incoming, bool stayInDepot, DoCommandFlag flags) { - Train *new_chain=0, - *remainder_chain=0, - *tmp_chain=0; - TileIndex tile = incoming->tile; - TemplateVehicle *tv = GetTemplateVehicleByGroupID(incoming->group_id); - EngineID eid = tv->engine_type; - - CommandCost buy(EXPENSES_NEW_VEHICLES); - CommandCost move_cost(EXPENSES_NEW_VEHICLES); - CommandCost tmp_result(EXPENSES_NEW_VEHICLES); - - - /* first some tests on necessity and sanity */ - if ( !tv ) - return buy; - bool need_replacement = !TrainMatchesTemplate(incoming, tv); - bool need_refit = !TrainMatchesTemplateRefit(incoming, tv); - bool use_refit = tv->refit_as_template; - CargoID store_refit_ct = CT_INVALID; - short store_refit_csubt = 0; - // if a train shall keep its old refit, store the refit setting of its first vehicle - if ( !use_refit ) { - for ( Train *getc=incoming; getc; getc=getc->GetNextUnit() ) - if ( getc->cargo_type != CT_INVALID ) { - store_refit_ct = getc->cargo_type; - break; - } - } - - // TODO: set result status to success/no success before returning - if ( !need_replacement ) { - if ( !need_refit || !use_refit ) { - /* before returning, release incoming train first if 2nd param says so */ - if ( !stayInDepot ) incoming->vehstatus &= ~VS_STOPPED; - return buy; - } - } else { - CommandCost buyCost = TestBuyAllTemplateVehiclesInChain(tv, tile); - if ( !buyCost.Succeeded() || !CheckCompanyHasMoney(buyCost) ) { - if ( !stayInDepot ) incoming->vehstatus &= ~VS_STOPPED; - return buy; - } - } - - /* define replacement behaviour */ - bool reuseDepot = tv->IsSetReuseDepotVehicles(); - bool keepRemainders = tv->IsSetKeepRemainingVehicles(); - - if ( need_replacement ) { - /// step 1: generate primary for newchain and generate remainder_chain - // 1. primary of incoming might already fit the template - // leave incoming's primary as is and move the rest to a free chain = remainder_chain - // 2. needed primary might be one of incoming's member vehicles - // 3. primary might be available as orphan vehicle in the depot - // 4. we need to buy a new engine for the primary - // all options other than 1. need to make sure to copy incoming's primary's status - if ( eid == incoming->engine_type ) { // 1 - new_chain = incoming; - remainder_chain = incoming->GetNextUnit(); - if ( remainder_chain ) - move_cost.AddCost(CmdMoveRailVehicle(tile, flags, remainder_chain->index|(1<<20), INVALID_VEHICLE, 0)); - } - else if ( (tmp_chain = ChainContainsEngine(eid, incoming)) && tmp_chain!=NULL ) { // 2 - // new_chain is the needed engine, move it to an empty spot in the depot - new_chain = tmp_chain; - move_cost.AddCost(DoCommand(tile, new_chain->index, INVALID_VEHICLE, flags,CMD_MOVE_RAIL_VEHICLE)); - remainder_chain = incoming; - } - else if ( reuseDepot && (tmp_chain = DepotContainsEngine(tile, eid, incoming)) && tmp_chain!=NULL ) { // 3 - new_chain = tmp_chain; - move_cost.AddCost(DoCommand(tile, new_chain->index, INVALID_VEHICLE, flags, CMD_MOVE_RAIL_VEHICLE)); - remainder_chain = incoming; - } - else { // 4 - tmp_result = DoCommand(tile, eid, 0, flags, CMD_BUILD_VEHICLE); - /* break up in case buying the vehicle didn't succeed */ - if ( !tmp_result.Succeeded() ) - return tmp_result; - buy.AddCost(tmp_result); - new_chain = Train::Get(_new_vehicle_id); - /* make sure the newly built engine is not attached to any free wagons inside the depot */ - move_cost.AddCost ( DoCommand(tile, new_chain->index, INVALID_VEHICLE, flags, CMD_MOVE_RAIL_VEHICLE) ); - /* prepare the remainder chain */ - remainder_chain = incoming; - } - // If we bought a new engine or reused one from the depot, copy some parameters from the incoming primary engine - if ( incoming != new_chain && flags == DC_EXEC) { - CopyHeadSpecificThings(incoming, new_chain, flags); - NeutralizeStatus(incoming); - // additionally, if we don't want to use the template refit, refit as incoming - // the template refit will be set further down, if we use it at all - if ( !use_refit ) { - uint32 cb = GetCmdRefitVeh(new_chain); - DoCommandP(new_chain->tile, new_chain->index, store_refit_ct | store_refit_csubt << 8 | 1 << 16 , cb); - } - - } - - /// step 2: fill up newchain according to the template - // foreach member of template (after primary): - // 1. needed engine might be within remainder_chain already - // 2. needed engine might be orphaned within the depot (copy status) - // 3. we need to buy (again) (copy status) - TemplateVehicle *cur_tmpl = tv->GetNextUnit(); - Train *last_veh = new_chain; - while (cur_tmpl) { - // 1. engine contained in remainder chain - if ( (tmp_chain = ChainContainsEngine(cur_tmpl->engine_type, remainder_chain)) && tmp_chain!=NULL ) { - // advance remainder_chain (if necessary) to not lose track of it - if ( tmp_chain == remainder_chain ) - remainder_chain = remainder_chain->GetNextUnit(); - move_cost.AddCost(CmdMoveRailVehicle(tile, flags, tmp_chain->index, last_veh->index, 0)); - } - // 2. engine contained somewhere else in the depot - else if ( reuseDepot && (tmp_chain = DepotContainsEngine(tile, cur_tmpl->engine_type, new_chain)) && tmp_chain!=NULL ) { - move_cost.AddCost(CmdMoveRailVehicle(tile, flags, tmp_chain->index, last_veh->index, 0)); - } - // 3. must buy new engine - else { - tmp_result = DoCommand(tile, cur_tmpl->engine_type, 0, flags, CMD_BUILD_VEHICLE); - if ( !tmp_result.Succeeded() ) - return tmp_result; - buy.AddCost(tmp_result); - tmp_chain = Train::Get(_new_vehicle_id); - move_cost.AddCost(CmdMoveRailVehicle(tile, flags, tmp_chain->index, last_veh->index, 0)); - } - // TODO: is this enough ? might it be that we bought a new wagon here and it now has std refit ? - if ( need_refit && flags == DC_EXEC ) { - if ( use_refit ) { - uint32 cb = GetCmdRefitVeh(tmp_chain); - DoCommandP(tmp_chain->tile, tmp_chain->index, cur_tmpl->cargo_type | cur_tmpl->cargo_subtype << 8 | 1 << 16 , cb); - // old - // CopyWagonStatus(cur_tmpl, tmp_chain); - } else { - uint32 cb = GetCmdRefitVeh(tmp_chain); - DoCommandP(tmp_chain->tile, tmp_chain->index, store_refit_ct | store_refit_csubt << 8 | 1 << 16 , cb); - } - } - cur_tmpl = cur_tmpl->GetNextUnit(); - last_veh = tmp_chain; - } - } - /* no replacement done */ - else { - new_chain = incoming; - } - /// step 3: reorder and neutralize the remaining vehicles from incoming - // wagons remaining from remainder_chain should be filled up in as few freewagonchains as possible - // each locos might be left as singular in the depot - // neutralize each remaining engine's status - - // refit, only if the template option is set so - if ( use_refit && (need_refit || need_replacement) ) { - RefitTrainFromTemplate(new_chain, tv); - } - - if ( new_chain && remainder_chain ) - for ( Train *ct=remainder_chain; ct; ct=ct->GetNextUnit() ) - TransferCargoForTrain(ct, new_chain); - - // point incoming to the newly created train so that starting/stopping from the calling function can be done - incoming = new_chain; - if ( !stayInDepot && flags == DC_EXEC ) - new_chain->vehstatus &= ~VS_STOPPED; - - if ( remainder_chain && keepRemainders && flags == DC_EXEC ) - BreakUpRemainders(remainder_chain); - else if ( remainder_chain ) { - buy.AddCost(DoCommand(tile, remainder_chain->index | (1<<20), 0, flags, CMD_SELL_VEHICLE)); - } - return buy; + new_head->ConsistChanged(CCF_LOADUNLOAD); } diff --git a/src/tbtr_template_vehicle_func.h b/src/tbtr_template_vehicle_func.h index b6926f4ba3..2078191090 100644 --- a/src/tbtr_template_vehicle_func.h +++ b/src/tbtr_template_vehicle_func.h @@ -8,6 +8,10 @@ #include "tbtr_template_vehicle.h" //void DrawTemplateVehicle(TemplateVehicle*, int, const Rect&); + + +Train* VirtualTrainFromTemplateVehicle(TemplateVehicle* tv); + void DrawTemplateVehicle(const TemplateVehicle*, int, int, int, VehicleID, int, VehicleID); void BuildTemplateGuiList(GUITemplateList*, Scrollbar*, Owner, RailType); @@ -26,9 +30,9 @@ TemplateVehicle *CreateNewTemplateVehicle(EngineID); void setupVirtTrain(const TemplateVehicle*, Train*); -TemplateVehicle* TemplateVehicleFromVirtualTrain(Train*); +TemplateVehicle* TemplateVehicleFromVirtualTrain(Train *virt); -Train* VirtualTrainFromTemplateVehicle(TemplateVehicle*); +//Train* VirtualTrainFromTemplateVehicle(TemplateVehicle*); inline TemplateVehicle* Last(TemplateVehicle*); @@ -51,16 +55,21 @@ Train* DepotContainsEngine(TileIndex, EngineID, Train*); int NumTrainsNeedTemplateReplacement(GroupID, TemplateVehicle*); -CommandCost TestBuyAllTemplateVehiclesInChain(Train*); CommandCost CalculateTemplateReplacementCost(Train*); +CommandCost TestBuyAllTemplateVehiclesInChain(TemplateVehicle *tv, TileIndex tile); + +void CmdRefitTrainFromTemplate(Train *t, TemplateVehicle *tv, DoCommandFlag); +void BreakUpRemainders(Train *t); short CountEnginesInChain(Train*); bool TemplateVehicleContainsEngineOfRailtype(const TemplateVehicle*, RailType); -Train* CloneVirtualTrainFromTrain(const Train *); -TemplateVehicle* CloneTemplateVehicleFromTrain(const Train *); - void TransferCargoForTrain(Train*, Train*); +void NeutralizeStatus(Train *t); + +bool TrainMatchesTemplate(const Train *t, TemplateVehicle *tv); +bool TrainMatchesTemplateRefit(const Train *t, TemplateVehicle *tv); + #endif diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 8256de1fcc..511669a40e 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -35,14 +35,15 @@ #include "order_backup.h" #include "zoom_func.h" #include "newgrf_debug.h" +#include "tbtr_template_vehicle_func.h" +#include "autoreplace_func.h" +#include "engine_func.h" #include "table/strings.h" #include "table/train_cmd.h" #include "safeguards.h" -#include "engine_func.h" - static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck); static bool TrainCheckIfLineEnds(Train *v, bool reverse = true); bool TrainController(Train *v, Vehicle *nomove, bool reverse = true); // Also used in vehicle_sl.cpp. @@ -4119,23 +4120,19 @@ Train* CmdBuildVirtualRailWagon(const Engine *e) AddArticulatedParts(v); + // Make sure we set EVERYTHING to virtual, even articulated parts. + for (Train* train_part = v; train_part != NULL; train_part = train_part->Next()) { + train_part->SetVirtual(); + } + _new_vehicle_id = v->index; - // from revision r22xxx - // VehicleMove(v, false); - // new v->UpdateViewport(true, false); - v->First()->ConsistChanged(ConsistChangeFlags::CCF_ARRANGE); - //UpdateTrainGroupID(v->First()); + v->First()->ConsistChanged(CCF_ARRANGE); CheckConsistencyOfArticulatedVehicle(v); - /* The GVSF_VIRTUAL flag is used to prevent depot-tile sanity checks */ - SetBit(v->subtype, GVSF_VIRTUAL); - -// GroupStatistics::CountVehicle( v, -1 ); - return v; } @@ -4150,13 +4147,18 @@ Train* CmdBuildVirtualRailWagon(const Engine *e) */ Train* CmdBuildVirtualRailVehicle(EngineID eid) { - if ( !IsEngineBuildable(eid, VEH_TRAIN, _current_company) ) return 0; + if (!IsEngineBuildable(eid, VEH_TRAIN, _current_company)) + return nullptr; + const Engine* e = Engine::Get(eid); const RailVehicleInfo *rvi = &e->u.rail; int num_vehicles = (e->u.rail.railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) + CountArticulatedParts(eid, false); - if ( !Train::CanAllocateItem(num_vehicles) ) return 0; - if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildVirtualRailWagon(e); + if (!Train::CanAllocateItem(num_vehicles)) + return nullptr; + + if (rvi->railveh_type == RAILVEH_WAGON) + return CmdBuildVirtualRailWagon(e); Train *v = new Train(); @@ -4191,9 +4193,6 @@ Train* CmdBuildVirtualRailVehicle(EngineID eid) v->SetFrontEngine(); v->SetEngine(); - // from revision r22xxx -// VehicleMove(v, false); - // new v->UpdateViewport(true, false); if (rvi->railveh_type == RAILVEH_MULTIHEAD) { @@ -4202,14 +4201,246 @@ Train* CmdBuildVirtualRailVehicle(EngineID eid) AddArticulatedParts(v); } - v->ConsistChanged(ConsistChangeFlags::CCF_ARRANGE); - //UpdateTrainGroupID(v); + // Make sure we set EVERYTHING to virtual, even articulated parts. + for (Train* train_part = v; train_part != NULL; train_part = train_part->Next()) { + train_part->SetVirtual(); + } + + v->ConsistChanged(CCF_ARRANGE); CheckConsistencyOfArticulatedVehicle(v); - SetBit(v->subtype, GVSF_VIRTUAL); - -// GroupStatistics::CountVehicle( v, -1 ); - return v; } + +/** + * Build a virtual train vehicle. + * @param tile unused + * @param flags type of operation + * @param p1 the engine ID to build + * @param p2 unused + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdBuildVirtualRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + EngineID eid = p1; + CommandCost cost = CommandCost(); + + bool should_execute = (flags & DC_EXEC) != 0; + + if (should_execute) { + Train* train = CmdBuildVirtualRailVehicle(eid); + + if (train == nullptr) + return CMD_ERROR; + } + + return CommandCost(); +} + +/** +* Replace a vehicle based on a template replacement order. +* @param tile unused +* @param flags type of operation +* @param p1 the ID of the vehicle to replace. +* @param p2 whether the vehicle should stay in the depot. +* @param text unused +* @return the cost of this operation or an error +*/ +CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + VehicleID vehicle_id = p1; + + Vehicle* vehicle = Vehicle::GetIfValid(vehicle_id); + + if (vehicle == nullptr || vehicle->type != VEH_TRAIN) + return CMD_ERROR; + + bool should_execute = (flags & DC_EXEC) != 0; + + if (!should_execute) + return CommandCost(); + + Train* incoming = Train::From(vehicle); + bool stayInDepot = p2 != 0; + + Train *new_chain = 0, + *remainder_chain = 0, + *tmp_chain = 0; + TemplateVehicle *tv = GetTemplateVehicleByGroupID(incoming->group_id); + EngineID eid = tv->engine_type; + + CommandCost buy(EXPENSES_NEW_VEHICLES); + CommandCost move_cost(EXPENSES_NEW_VEHICLES); + CommandCost tmp_result(EXPENSES_NEW_VEHICLES); + + + /* first some tests on necessity and sanity */ + if (!tv) + return buy; + bool need_replacement = !TrainMatchesTemplate(incoming, tv); + bool need_refit = !TrainMatchesTemplateRefit(incoming, tv); + bool use_refit = tv->refit_as_template; + CargoID store_refit_ct = CT_INVALID; + short store_refit_csubt = 0; + // if a train shall keep its old refit, store the refit setting of its first vehicle + if (!use_refit) { + for (Train *getc = incoming; getc; getc = getc->GetNextUnit()) + if (getc->cargo_type != CT_INVALID) { + store_refit_ct = getc->cargo_type; + break; + } + } + + // TODO: set result status to success/no success before returning + if (!need_replacement) { + if (!need_refit || !use_refit) { + /* before returning, release incoming train first if 2nd param says so */ + if (!stayInDepot) incoming->vehstatus &= ~VS_STOPPED; + return buy; + } + } + else { + CommandCost buyCost = TestBuyAllTemplateVehiclesInChain(tv, tile); + if (!buyCost.Succeeded() || !CheckCompanyHasMoney(buyCost)) { + if (!stayInDepot) incoming->vehstatus &= ~VS_STOPPED; + return buy; + } + } + + /* define replacement behavior */ + bool reuseDepot = tv->IsSetReuseDepotVehicles(); + bool keepRemainders = tv->IsSetKeepRemainingVehicles(); + + if (need_replacement) { + /// step 1: generate primary for newchain and generate remainder_chain + // 1. primary of incoming might already fit the template + // leave incoming's primary as is and move the rest to a free chain = remainder_chain + // 2. needed primary might be one of incoming's member vehicles + // 3. primary might be available as orphan vehicle in the depot + // 4. we need to buy a new engine for the primary + // all options other than 1. need to make sure to copy incoming's primary's status + if (eid == incoming->engine_type) { // 1 + new_chain = incoming; + remainder_chain = incoming->GetNextUnit(); + if (remainder_chain) + move_cost.AddCost(CmdMoveRailVehicle(tile, flags, remainder_chain->index | (1 << 20), INVALID_VEHICLE, 0)); + } + else if ((tmp_chain = ChainContainsEngine(eid, incoming)) && tmp_chain != NULL) { // 2 + // new_chain is the needed engine, move it to an empty spot in the depot + new_chain = tmp_chain; + move_cost.AddCost(DoCommand(tile, new_chain->index, INVALID_VEHICLE, flags, CMD_MOVE_RAIL_VEHICLE)); + remainder_chain = incoming; + } + else if (reuseDepot && (tmp_chain = DepotContainsEngine(tile, eid, incoming)) && tmp_chain != NULL) { // 3 + new_chain = tmp_chain; + move_cost.AddCost(DoCommand(tile, new_chain->index, INVALID_VEHICLE, flags, CMD_MOVE_RAIL_VEHICLE)); + remainder_chain = incoming; + } + else { // 4 + tmp_result = DoCommand(tile, eid, 0, flags, CMD_BUILD_VEHICLE); + /* break up in case buying the vehicle didn't succeed */ + if (!tmp_result.Succeeded()) + return tmp_result; + buy.AddCost(tmp_result); + new_chain = Train::Get(_new_vehicle_id); + /* make sure the newly built engine is not attached to any free wagons inside the depot */ + move_cost.AddCost(DoCommand(tile, new_chain->index, INVALID_VEHICLE, flags, CMD_MOVE_RAIL_VEHICLE)); + /* prepare the remainder chain */ + remainder_chain = incoming; + } + // If we bought a new engine or reused one from the depot, copy some parameters from the incoming primary engine + if (incoming != new_chain && flags == DC_EXEC) { + CopyHeadSpecificThings(incoming, new_chain, flags); + NeutralizeStatus(incoming); + + + // additionally, if we don't want to use the template refit, refit as incoming + // the template refit will be set further down, if we use it at all + if (!use_refit) { + uint32 cb = GetCmdRefitVeh(new_chain); + DoCommand(new_chain->tile, new_chain->index, store_refit_ct | store_refit_csubt << 8 | 1 << 16 | (1 << 5), flags, cb); + } + + } + + /// step 2: fill up newchain according to the template + // foreach member of template (after primary): + // 1. needed engine might be within remainder_chain already + // 2. needed engine might be orphaned within the depot (copy status) + // 3. we need to buy (again) (copy status) + TemplateVehicle *cur_tmpl = tv->GetNextUnit(); + Train *last_veh = new_chain; + while (cur_tmpl) { + // 1. engine contained in remainder chain + if ((tmp_chain = ChainContainsEngine(cur_tmpl->engine_type, remainder_chain)) && tmp_chain != NULL) { + // advance remainder_chain (if necessary) to not lose track of it + if (tmp_chain == remainder_chain) + remainder_chain = remainder_chain->GetNextUnit(); + move_cost.AddCost(CmdMoveRailVehicle(tile, flags, tmp_chain->index, last_veh->index, 0)); + } + // 2. engine contained somewhere else in the depot + else if (reuseDepot && (tmp_chain = DepotContainsEngine(tile, cur_tmpl->engine_type, new_chain)) && tmp_chain != NULL) { + move_cost.AddCost(CmdMoveRailVehicle(tile, flags, tmp_chain->index, last_veh->index, 0)); + } + // 3. must buy new engine + else { + tmp_result = DoCommand(tile, cur_tmpl->engine_type, 0, flags, CMD_BUILD_VEHICLE); + if (!tmp_result.Succeeded()) + return tmp_result; + buy.AddCost(tmp_result); + tmp_chain = Train::Get(_new_vehicle_id); + move_cost.AddCost(CmdMoveRailVehicle(tile, flags, tmp_chain->index, last_veh->index, 0)); + } + // TODO: is this enough ? might it be that we bought a new wagon here and it now has std refit ? + if (need_refit && flags == DC_EXEC) { + if (use_refit) { + uint32 cb = GetCmdRefitVeh(tmp_chain); + DoCommand(tmp_chain->tile, tmp_chain->index, cur_tmpl->cargo_type | cur_tmpl->cargo_subtype << 8 | 1 << 16 | (1 << 5), flags, cb); + // old + // CopyWagonStatus(cur_tmpl, tmp_chain); + } + else { + uint32 cb = GetCmdRefitVeh(tmp_chain); + DoCommand(tmp_chain->tile, tmp_chain->index, store_refit_ct | store_refit_csubt << 8 | 1 << 16 | (1 << 5), flags, cb); + } + } + cur_tmpl = cur_tmpl->GetNextUnit(); + last_veh = tmp_chain; + } + } + /* no replacement done */ + else { + new_chain = incoming; + } + /// step 3: reorder and neutralize the remaining vehicles from incoming + // wagons remaining from remainder_chain should be filled up in as few freewagonchains as possible + // each locos might be left as singular in the depot + // neutralize each remaining engine's status + + // refit, only if the template option is set so + if (use_refit && (need_refit || need_replacement)) { + CmdRefitTrainFromTemplate(new_chain, tv, flags); + } + + if (new_chain && remainder_chain) + for (Train *ct = remainder_chain; ct; ct = ct->GetNextUnit()) + TransferCargoForTrain(ct, new_chain); + + // point incoming to the newly created train so that starting/stopping from the calling function can be done + incoming = new_chain; + if (!stayInDepot && flags == DC_EXEC) + new_chain->vehstatus &= ~VS_STOPPED; + + if (remainder_chain && keepRemainders && flags == DC_EXEC) + BreakUpRemainders(remainder_chain); + else if (remainder_chain) { + buy.AddCost(DoCommand(tile, remainder_chain->index | (1 << 20), 0, flags, CMD_SELL_VEHICLE)); + } + + /* Redraw main gui for changed statistics */ + SetWindowClassesDirty(WC_TEMPLATEGUI_MAIN); + + return buy; +} diff --git a/src/vehicle.cpp b/src/vehicle.cpp index d9f3afbd30..139fe559eb 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1032,9 +1032,7 @@ void CallVehicleTicks() bool stayInDepot = it->second; it->first->vehstatus |= VS_STOPPED; - CmdTemplateReplaceVehicle(t, stayInDepot, DC_EXEC); - /* Redraw main gui for changed statistics */ - SetWindowClassesDirty(WC_TEMPLATEGUI_MAIN); + DoCommand(t->tile, t->index, stayInDepot ? 1 : 0, DC_EXEC, CMD_TEMPLATE_REPLACE_VEHICLE); } tmpl_cur_company.Restore(); } diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index c8fee79095..fc817bc213 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -31,6 +31,8 @@ #include "ship.h" #include "newgrf.h" #include "company_base.h" +#include "tbtr_template_vehicle.h" +#include "tbtr_template_vehicle_func.h" #include "table/strings.h" @@ -174,7 +176,10 @@ CommandCost CmdSellVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 if (front->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_VEHICLE_IS_DESTROYED); - if (!front->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type); + /* Do this check only if the vehicle to be moved is non-virtual */ + if (!HasBit(p1, 21)) { + if (!front->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type); + } /* Can we actually make the order backup, i.e. are there enough orders? */ if (p1 & MAKE_ORDER_BACKUP_FLAG && @@ -776,6 +781,442 @@ static void CloneVehicleName(const Vehicle *src, Vehicle *dst) /* All done. If we didn't find a name, it'll just use its default. */ } +inline void SetupTemplateVehicleFromVirtual(TemplateVehicle *tmp, TemplateVehicle *prev, Train *virt) +{ + if (prev) { + prev->SetNext(tmp); + tmp->SetPrev(prev); + tmp->SetFirst(prev->First()); + } + tmp->railtype = virt->railtype; + tmp->owner = virt->owner; + tmp->value = virt->value; + + // set the subtype but also clear the virtual flag while doing it + tmp->subtype = virt->subtype & ~(1 << GVSF_VIRTUAL); + // set the cargo type and capacity + tmp->cargo_type = virt->cargo_type; + tmp->cargo_subtype = virt->cargo_subtype; + tmp->cargo_cap = virt->cargo_cap; + + const GroundVehicleCache *gcache = virt->GetGroundVehicleCache(); + tmp->max_speed = virt->GetDisplayMaxSpeed(); + tmp->power = gcache->cached_power; + tmp->weight = gcache->cached_weight; + tmp->max_te = gcache->cached_max_te / 1000; + + tmp->spritenum = virt->spritenum; + tmp->cur_image = virt->GetImage(DIR_W, EIT_PURCHASE); + Point *p = new Point(); + tmp->image_width = virt->GetDisplayImageWidth(p); +} + +/** + * Toggles 'reuse depot vehicles' on a template vehicle. + * @param tile unused + * @param flags type of operation + * @param p1 the template vehicle's index + * @param p2 unused + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdToggleReuseDepotVehicles(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + // Identify template to toggle + TemplateVehicle *template_vehicle = TemplateVehicle::GetIfValid(p1); + + if (template_vehicle == NULL) + return CMD_ERROR; + + bool should_execute = (flags & DC_EXEC) != 0; + + if (should_execute) { + template_vehicle->ToggleReuseDepotVehicles(); + + InvalidateWindowClassesData(WC_TEMPLATEGUI_MAIN, 0); + } + + return CommandCost(); +} + +/** + * Toggles 'keep remaining vehicles' on a template vehicle. + * @param tile unused + * @param flags type of operation + * @param p1 the template vehicle's index + * @param p2 unused + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdToggleKeepRemainingVehicles(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + // Identify template to toggle + TemplateVehicle *template_vehicle = TemplateVehicle::GetIfValid(p1); + + if (template_vehicle == NULL) + return CMD_ERROR; + + bool should_execute = (flags & DC_EXEC) != 0; + + if (should_execute) { + template_vehicle->ToggleKeepRemainingVehicles(); + + InvalidateWindowClassesData(WC_TEMPLATEGUI_MAIN, 0); + } + + return CommandCost(); +} + +/** + * Toggles 'refit as template' on a template vehicle. + * @param tile unused + * @param flags type of operation + * @param p1 the template vehicle's index + * @param p2 unused + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdToggleRefitAsTemplate(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + // Identify template to toggle + TemplateVehicle *template_vehicle = TemplateVehicle::GetIfValid(p1); + + if (template_vehicle == NULL) + return CMD_ERROR; + + bool should_execute = (flags & DC_EXEC) != 0; + + if (should_execute) { + template_vehicle->ToggleRefitAsTemplate(); + + InvalidateWindowClassesData(WC_TEMPLATEGUI_MAIN, 0); + } + + return CommandCost(); +} + +/** + * Create a virtual train from a template vehicle. + * @param tile unused + * @param flags type of operation + * @param p1 the original vehicle's index + * @param p2 unused + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdVirtualTrainFromTemplateVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + VehicleID template_vehicle_id = p1; + + TemplateVehicle* tv = TemplateVehicle::GetIfValid(template_vehicle_id); + + if (tv == NULL) + return CMD_ERROR; + + bool should_execute = (flags & DC_EXEC) != 0; + + if (should_execute) { + Train* train = VirtualTrainFromTemplateVehicle(tv); + + if (train == nullptr) + return CMD_ERROR; + } + + return CommandCost(); +} + +Train* VirtualTrainFromTemplateVehicle(TemplateVehicle* tv) +{ + CommandCost c; + Train *tmp, *head, *tail; + + head = CmdBuildVirtualRailVehicle(tv->engine_type); + if ( !head ) return nullptr; + + tail = head; + tv = tv->GetNextUnit(); + while ( tv ) { + tmp = CmdBuildVirtualRailVehicle(tv->engine_type); + if ( tmp ) { + tmp->cargo_type = tv->cargo_type; + tmp->cargo_subtype = tv->cargo_subtype; + CmdMoveRailVehicle(INVALID_TILE, DC_EXEC, (1<<21) | tmp->index, tail->index, 0); + tail = tmp; + } + tv = tv->GetNextUnit(); + } + + _new_vehicle_id = head->index; + + return head; +} + +/** + * Create a virtual train from a regular train. + * @param tile unused + * @param flags type of operation + * @param p1 the train index + * @param p2 unused + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdVirtualTrainFromTrain(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + VehicleID vehicle_id = p1; + Vehicle* vehicle = Vehicle::GetIfValid(vehicle_id); + + if (vehicle == nullptr || vehicle->type != VEH_TRAIN) + return CMD_ERROR; + + Train* train = Train::From(vehicle); + + bool should_execute = (flags & DC_EXEC) != 0; + + if (should_execute) { + CommandCost c; + Train *tmp, *head, *tail; + + head = CmdBuildVirtualRailVehicle(train->engine_type); + if ( !head ) return CMD_ERROR; + + tail = head; + train = train->GetNextUnit(); + while ( train ) { + tmp = CmdBuildVirtualRailVehicle(train->engine_type); + if ( tmp ) { + tmp->cargo_type = train->cargo_type; + tmp->cargo_subtype = train->cargo_subtype; + CmdMoveRailVehicle(0, DC_EXEC, (1<<21) | tmp->index, tail->index, 0); + tail = tmp; + } + train = train->GetNextUnit(); + } + + _new_vehicle_id = head->index; + } + + return CommandCost(); +} + +/** + * Create a virtual train from a template vehicle. + * @param tile unused + * @param flags type of operation + * @param p1 the vehicle's index + * @param p2 unused + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdDeleteVirtualTrain(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + VehicleID vehicle_id = p1; + + Vehicle* vehicle = Vehicle::GetIfValid(vehicle_id); + + if (vehicle == nullptr || vehicle->type != VEH_TRAIN) + return CMD_ERROR; + + Train* train = Train::From(vehicle); + + bool should_execute = (flags & DC_EXEC) != 0; + + if (should_execute) { + delete train; + } + + return CommandCost(); +} + +/** + * Replace a template vehicle with another one based on a virtual train. + * @param tile unused + * @param flags type of operation + * @param p1 the template vehicle's index + * @param p2 the virtual train's index + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdReplaceTemplateVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + VehicleID template_vehicle_id = p1; + VehicleID virtual_train_id = p2; + + TemplateVehicle* template_vehicle = TemplateVehicle::GetIfValid(template_vehicle_id); + Vehicle* vehicle = Vehicle::GetIfValid(virtual_train_id); + + if (vehicle == nullptr || vehicle->type != VEH_TRAIN) + return CMD_ERROR; + + Train* train = Train::From(vehicle); + + bool should_execute = (flags & DC_EXEC) != 0; + + if (should_execute) { + VehicleID old_ID = INVALID_VEHICLE; + + if (template_vehicle != nullptr) { + old_ID = template_vehicle->index; + delete template_vehicle; + template_vehicle = nullptr; + } + + template_vehicle = TemplateVehicleFromVirtualTrain(train); + + if (template_vehicle == nullptr) + return CMD_ERROR; + + // Make sure our replacements still point to the correct thing. + if (old_ID != template_vehicle->index) { + TemplateReplacement* tr; + FOR_ALL_TEMPLATE_REPLACEMENTS(tr) { + if (tr->GetTemplateVehicleID() == old_ID) { + tr->SetTemplate(template_vehicle->index); + } + } + } + + InvalidateWindowClassesData(WC_TEMPLATEGUI_MAIN, 0); + } + + return CommandCost(); +} + +/** + * Clone a vehicle to create a template vehicle. + * @param tile unused + * @param flags type of operation + * @param p1 the original vehicle's index + * @param p2 unused + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdTemplateVehicleFromTrain(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + // create a new template from the clicked vehicle + TemplateVehicle *tv; + + Vehicle *t = Vehicle::GetIfValid(p1); + + Train *clicked = Train::GetIfValid(t->index); + if (!clicked) + return CMD_ERROR; + + Train *init_clicked = clicked; + + int len = CountVehiclesInChain(clicked); + if (!TemplateVehicle::CanAllocateItem(len)) + return CMD_ERROR; + + bool should_execute = (flags & DC_EXEC) != 0; + + if (should_execute) { + TemplateVehicle *tmp, *prev=0; + for (; clicked; clicked=clicked->Next()) { + tmp = new TemplateVehicle(clicked->engine_type); + SetupTemplateVehicleFromVirtual(tmp, prev, clicked); + prev = tmp; + } + + tmp->First()->SetRealLength(CeilDiv(init_clicked->gcache.cached_total_length * 10, TILE_SIZE)); + tv = tmp->First(); + + if (!tv) return CMD_ERROR; + + InvalidateWindowClassesData(WC_TEMPLATEGUI_MAIN, 0); + } + + return CommandCost(); +} + +/** + * Delete a template vehicle. + * @param tile unused + * @param flags type of operation + * @param p1 the template vehicle's index + * @param p2 unused + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdDeleteTemplateVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + // Identify template to delete + TemplateVehicle *del = TemplateVehicle::GetIfValid(p1); + + if (del == NULL) + return CMD_ERROR; + + bool should_execute = (flags & DC_EXEC) != 0; + + if (should_execute) { + // Remove a corresponding template replacement if existing + TemplateReplacement *tr = GetTemplateReplacementByTemplateID(del->index); + if (tr != NULL) { + delete tr; + } + + delete del; + + InvalidateWindowClassesData(WC_TEMPLATEGUI_MAIN, 0); + } + + return CommandCost(); +} + +/** + * Issues a template replacement for a vehicle group + * @param tile unused + * @param flags type of operation + * @param p1 the group index + * @param p2 the template vehicle's index + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdIssueTemplateReplacement(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + bool should_execute = (flags & DC_EXEC) != 0; + + GroupID group_id = p1; + TemplateID template_id = p2; + + if (should_execute) { + bool succeeded = IssueTemplateReplacement(group_id, template_id); + + if (!succeeded) + return CMD_ERROR; + + InvalidateWindowClassesData(WC_TEMPLATEGUI_MAIN, 0); + } + + return CommandCost(); +} + +/** + * Deletes a template replacement from a vehicle group + * @param tile unused + * @param flags type of operation + * @param p1 the group index + * @param p2 unused + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdDeleteTemplateReplacement(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + bool should_execute = (flags & DC_EXEC) != 0; + + GroupID group_id = p1; + + if (should_execute) { + TemplateReplacement* tr = GetTemplateReplacementByGroupID(group_id); + if (tr != NULL) + delete tr; + + InvalidateWindowClassesData(WC_TEMPLATEGUI_MAIN, 0); + } + + return CommandCost(); +} + + /** * Clone a vehicle. If it is a train, it will clone all the cars too * @param tile tile of the depot where the cloned vehicle is build @@ -1020,6 +1461,30 @@ CommandCost CmdSendVehicleToDepot(TileIndex tile, DoCommandFlag flags, uint32 p1 return v->SendToDepot(flags, (DepotCommand)(p1 & DEPOT_COMMAND_MASK)); } +/** + * Sets the vehicle unit number + * @param tile unused + * @param flags type of operation + * @param p1 vehicle ID to set number on + * @param p2 vehicle unit number + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdSetVehicleUnitNumber(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + Vehicle *v = Vehicle::GetIfValid(p1); + if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; + + CommandCost ret = CheckOwnership(v->owner); + if (ret.Failed()) return ret; + + if (flags & DC_EXEC) { + v->unitnumber = (UnitID)p2; + } + + return CommandCost(); +} + /** * Give a custom name to your vehicle * @param tile unused From a31e7ac87d4d619c69af26c65064f46e5a1b65ae Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 14 Feb 2016 02:30:03 +0000 Subject: [PATCH 06/15] Initial whitespace, formatting, file headers and NULL usage fixes. --- src/group_gui.cpp | 6 +- src/lang/english.txt | 106 +++---- src/order_cmd.cpp | 2 +- src/tbtr_template_gui_create.cpp | 100 ++++--- src/tbtr_template_gui_create.h | 11 +- src/tbtr_template_gui_create_virtualtrain.cpp | 35 +-- src/tbtr_template_gui_create_virtualtrain.h | 11 + src/tbtr_template_gui_main.cpp | 157 ++++++----- src/tbtr_template_gui_main.h | 11 +- src/tbtr_template_gui_replaceall.cpp | 163 ++++++----- src/tbtr_template_gui_replaceall.h | 34 +-- src/tbtr_template_vehicle.cpp | 111 ++++---- src/tbtr_template_vehicle.h | 45 ++- src/tbtr_template_vehicle_func.cpp | 263 +++++++++--------- src/tbtr_template_vehicle_func.h | 17 +- src/train.h | 4 +- src/train_cmd.cpp | 108 +++---- src/vehicle.cpp | 19 +- src/vehicle_base.h | 4 +- src/vehicle_cmd.cpp | 84 +++--- src/vehicle_gui.cpp | 6 +- src/viewport.cpp | 2 +- src/widgets/build_vehicle_widget.h | 1 - 23 files changed, 712 insertions(+), 588 deletions(-) diff --git a/src/group_gui.cpp b/src/group_gui.cpp index 08a458f642..e286f879e0 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -25,6 +25,7 @@ #include "vehicle_gui_base.h" #include "core/geometry_func.hpp" #include "company_base.h" +#include "tbtr_template_gui_main.h" #include "widgets/group_widget.h" @@ -34,8 +35,6 @@ static const int LEVEL_WIDTH = 10; ///< Indenting width of a sub-group in pixels -#include "tbtr_template_gui_main.h" - typedef GUIList GUIGroupList; static const NWidgetPart _nested_group_widgets[] = { @@ -787,8 +786,9 @@ public: switch (index) { case ADI_TEMPLATE_REPLACE: // TemplateReplace Window - if ( vli.vtype == VEH_TRAIN ) + if (vli.vtype == VEH_TRAIN) { ShowTemplateReplaceWindow(this->unitnumber_digits, this->resize.step_height); + } break; case ADI_REPLACE: // Replace window ShowReplaceGroupVehicleWindow(this->vli.index, this->vli.vtype); diff --git a/src/lang/english.txt b/src/lang/english.txt index c21cde0b3d..cad97b1066 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -4969,61 +4969,61 @@ STR_SHIP :{BLACK}{SHIP} STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY}) -STR_TMPL_RPL_TITLE :{WHITE}Template Replacement -STR_TMPL_TEMPLATE_REPLACEMENT :Template Replacement -STR_TMPL_TRAINS_IN_GROUP :{BLACK}Trains in group -STR_TMPL_AVAILABLE_TEMPLATES :{BLACK}Available Templates -STR_TMPL_DEFINE_TEMPLATE :{BLACK}New -STR_TMPL_EDIT_TEMPLATE :{BLACK}Edit -STR_TMPL_CREATE_CLONE_VEH :{BLACK}Clone -STR_TMPL_DELETE_TEMPLATE :{BLACK}Delete -STR_TMPL_RPL_ALL_TMPL :{BLACK}Replace All Templates -STR_TMPL_NEW_VEHICLE :{BLACK}New Vehicle -STR_TMPL_CONFIRM :{BLACK}Ok -STR_TMPL_CANCEL :{BLACK}Cancel -STR_TMPL_NEW :{BLACK}New Template Vehicle -STR_TMPL_REFIT :{BLACK}Refit -STR_TMPL_GROUP_INFO :{BLACK}Group Info: {ORANGE} -STR_TMPL_TEMPLATE_INFO :{BLACK}Template Info: {ORANGE} -STR_TMPL_RPL_START :{BLACK}Start replacing -STR_TMPL_RPL_STOP :{BLACK}Stop replacing -STR_TMPL_TRAIN_OVR_VALUE :{TINY_FONT}{BLACK}Train Value: {CURRENCY_SHORT} -STR_TMPL_TEMPLATE_OVR_VALUE :{TINY_FONT}{BLACK}Buying Cost: {GOLD}{CURRENCY_LONG} -STR_TMPL_TEMPLATE_OVR_VALUE_nogold :{TINY_FONT}{BLACK}Buying Cost: {CURRENCY_LONG} -STR_TMPL_TEMPLATE_OVR_VALUE_nogoldandcurrency :{TINY_FONT}{BLACK}Buying Cost: -STR_TMPL_TEMPLATE_OVR_VALUE_notinyfont :{BLACK}Buying Cost: {GOLD}{CURRENCY_LONG} -STR_TMPL_TEMPLATE_OVR_VALUE_notinyfontandblack :Buying Cost: {GOLD}{CURRENCY_LONG} -STR_TMPL_WARNING_FREE_WAGON :{RED}Free Chain: not runnable! -STR_TMPL_TEST :{ORANGE}Test String: {RAW_STRING} {RAW_STRING} -STR_TMPL_GROUP_USES_TEMPLATE :{BLACK}Template in use: {NUM} -STR_TMP_TEMPLATE_IN_USE :Template is in use -STR_TMPL_GROUP_NUM_TRAINS :{BLACK}{NUM} -STR_TMPL_CREATEGUI_TITLE :{WHITE}Create/Edit Template Vehicle -STR_TMPL_MAINGUI_DEFINEDGROUPS :{BLACK}Defined Groups for Company -STR_TMPL_TMPLRPL_EX_DIFF_RAILTYPE :Uses Template of different rail type +STR_TMPL_RPL_TITLE :{WHITE}Template Replacement +STR_TMPL_TEMPLATE_REPLACEMENT :Template Replacement +STR_TMPL_TRAINS_IN_GROUP :{BLACK}Trains in group +STR_TMPL_AVAILABLE_TEMPLATES :{BLACK}Available Templates +STR_TMPL_DEFINE_TEMPLATE :{BLACK}New +STR_TMPL_EDIT_TEMPLATE :{BLACK}Edit +STR_TMPL_CREATE_CLONE_VEH :{BLACK}Clone +STR_TMPL_DELETE_TEMPLATE :{BLACK}Delete +STR_TMPL_RPL_ALL_TMPL :{BLACK}Replace All Templates +STR_TMPL_NEW_VEHICLE :{BLACK}New Vehicle +STR_TMPL_CONFIRM :{BLACK}Ok +STR_TMPL_CANCEL :{BLACK}Cancel +STR_TMPL_NEW :{BLACK}New Template Vehicle +STR_TMPL_REFIT :{BLACK}Refit +STR_TMPL_GROUP_INFO :{BLACK}Group Info: {ORANGE} +STR_TMPL_TEMPLATE_INFO :{BLACK}Template Info: {ORANGE} +STR_TMPL_RPL_START :{BLACK}Start replacing +STR_TMPL_RPL_STOP :{BLACK}Stop replacing +STR_TMPL_TRAIN_OVR_VALUE :{TINY_FONT}{BLACK}Train Value: {CURRENCY_SHORT} +STR_TMPL_TEMPLATE_OVR_VALUE :{TINY_FONT}{BLACK}Buying Cost: {GOLD}{CURRENCY_LONG} +STR_TMPL_TEMPLATE_OVR_VALUE_nogold :{TINY_FONT}{BLACK}Buying Cost: {CURRENCY_LONG} +STR_TMPL_TEMPLATE_OVR_VALUE_nogoldandcurrency :{TINY_FONT}{BLACK}Buying Cost: +STR_TMPL_TEMPLATE_OVR_VALUE_notinyfont :{BLACK}Buying Cost: {GOLD}{CURRENCY_LONG} +STR_TMPL_TEMPLATE_OVR_VALUE_notinyfontandblack :Buying Cost: {GOLD}{CURRENCY_LONG} +STR_TMPL_WARNING_FREE_WAGON :{RED}Free Chain: not runnable! +STR_TMPL_TEST :{ORANGE}Test String: {RAW_STRING} {RAW_STRING} +STR_TMPL_GROUP_USES_TEMPLATE :{BLACK}Template in use: {NUM} +STR_TMP_TEMPLATE_IN_USE :Template is in use +STR_TMPL_GROUP_NUM_TRAINS :{BLACK}{NUM} +STR_TMPL_CREATEGUI_TITLE :{WHITE}Create/Edit Template Vehicle +STR_TMPL_MAINGUI_DEFINEDGROUPS :{BLACK}Defined Groups for Company +STR_TMPL_TMPLRPL_EX_DIFF_RAILTYPE :Uses Template of different rail type -STR_TMPL_SET_USEDEPOT :{BLACK}Use vehicles in depot -STR_TMPL_SET_USEDEPOT_TIP :{BLACK}Use vehicles inside the depot that are in a neutral and idle state to compose trains on template replacement in order to reduce buying costs -STR_TMPL_SET_KEEPREMAINDERS :{BLACK}Keep remainders -STR_TMPL_SET_KEEPREMAINDERS_TIP :{BLACK}After finishing template replacement keep all remaining vehicles from the old train in a neutral and idle state for later use -STR_TMPL_SET_REFIT :{BLACK}Use Refit -STR_TMPL_SET_REFIT_TIP :{BLACK}If set, the train will use exactly the cargo refit specified by the template. If not every wagon that is to be newly bought or retrieved from the depot, will *attempt* to be refitted as the old one was. Standard refit if this is impossible. +STR_TMPL_SET_USEDEPOT :{BLACK}Use vehicles in depot +STR_TMPL_SET_USEDEPOT_TIP :{BLACK}Use vehicles inside the depot that are in a neutral and idle state to compose trains on template replacement in order to reduce buying costs +STR_TMPL_SET_KEEPREMAINDERS :{BLACK}Keep remainders +STR_TMPL_SET_KEEPREMAINDERS_TIP :{BLACK}After finishing template replacement keep all remaining vehicles from the old train in a neutral and idle state for later use +STR_TMPL_SET_REFIT :{BLACK}Use Refit +STR_TMPL_SET_REFIT_TIP :{BLACK}If set, the train will use exactly the cargo refit specified by the template. If not every wagon that is to be newly bought or retrieved from the depot, will *attempt* to be refitted as the old one was. Standard refit if this is impossible. -STR_TMPL_CONFIG_USEDEPOT :use depot -STR_TMPL_CONFIG_KEEPREMAINDERS :keep rem -STR_TMPL_CONFIG_REFIT :refit +STR_TMPL_CONFIG_USEDEPOT :use depot +STR_TMPL_CONFIG_KEEPREMAINDERS :keep rem +STR_TMPL_CONFIG_REFIT :refit -STR_TMPL_NUM_TRAINS_NEED_RPL :# trains to replace: +STR_TMPL_NUM_TRAINS_NEED_RPL :# trains to replace: -STR_TMPL_CARGO_SUMMARY :{CARGO_LONG} -STR_TMPL_CARGO_SUMMARY_MULTI :{CARGO_LONG} (x{NUM}) +STR_TMPL_CARGO_SUMMARY :{CARGO_LONG} +STR_TMPL_CARGO_SUMMARY_MULTI :{CARGO_LONG} (x{NUM}) -STR_TMPL_RPLALLGUI_TITLE :{WHITE}Replace all Templace Vehicles -STR_TMPL_RPLALLGUI_INSET_TOP :{BLACK}Choose Vehicle Type and Replacement -STR_TMPL_RPLALLGUI_INSET_TOP_1 :{BLACK}Template Engines -STR_TMPL_RPLALLGUI_INSET_TOP_2 :{BLACK}Buyable Engines -STR_TMPL_RPLALLGUI_INSET_BOTTOM :{BLACK}Current Template List (updated only after replacement) -STR_TMPL_RPLALLGUI_BUTTON_RPLALL :{BLACK}Replace All -STR_TMPL_RPLALLGUI_BUTTON_APPLY :{BLACK}Apply -STR_TMPL_RPLALLGUI_BUTTON_CANCEL :{BLACK}Cancel -STR_TMPL_RPLALLGUI_USE_TIP :{BLACK}Select a vehicle type from each list and press 'Replace All'. If you are happy with the result displayed in the template list, press 'Apply' to actually apply these changes. +STR_TMPL_RPLALLGUI_TITLE :{WHITE}Replace all Templace Vehicles +STR_TMPL_RPLALLGUI_INSET_TOP :{BLACK}Choose Vehicle Type and Replacement +STR_TMPL_RPLALLGUI_INSET_TOP_1 :{BLACK}Template Engines +STR_TMPL_RPLALLGUI_INSET_TOP_2 :{BLACK}Buyable Engines +STR_TMPL_RPLALLGUI_INSET_BOTTOM :{BLACK}Current Template List (updated only after replacement) +STR_TMPL_RPLALLGUI_BUTTON_RPLALL :{BLACK}Replace All +STR_TMPL_RPLALLGUI_BUTTON_APPLY :{BLACK}Apply +STR_TMPL_RPLALLGUI_BUTTON_CANCEL :{BLACK}Cancel +STR_TMPL_RPLALLGUI_USE_TIP :{BLACK}Select a vehicle type from each list and press 'Replace All'. If you are happy with the result displayed in the template list, press 'Apply' to actually apply these changes. diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 650d1aef01..1124bea45f 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -1772,7 +1772,7 @@ void CheckOrders(const Vehicle *v) /* Only check every 20 days, so that we don't flood the message log */ /* The check is skipped entirely in case the current vehicle is virtual (a.k.a a 'template train') */ - if (v->owner == _local_company && v->day_counter % 20 == 0 && !HasBit(v->subtype, GVSF_VIRTUAL) ) { + if (v->owner == _local_company && v->day_counter % 20 == 0 && !HasBit(v->subtype, GVSF_VIRTUAL)) { const Order *order; StringID message = INVALID_STRING_ID; diff --git a/src/tbtr_template_gui_create.cpp b/src/tbtr_template_gui_create.cpp index c7a475d1ac..741b840716 100644 --- a/src/tbtr_template_gui_create.cpp +++ b/src/tbtr_template_gui_create.cpp @@ -1,3 +1,14 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file tbtr_template_gui_create.cpp Template-based train replacement: template creation GUI. */ + #include "stdafx.h" #include "gfx_func.h" @@ -29,12 +40,13 @@ #include "order_backup.h" #include "group.h" #include "company_base.h" +#include "train.h" #include "tbtr_template_gui_create.h" #include "tbtr_template_vehicle.h" #include "tbtr_template_vehicle_func.h" -#include "train.h" +#include "safeguards.h" class TemplateReplaceWindow; @@ -83,13 +95,13 @@ static const NWidgetPart _widgets[] = { }; static WindowDesc _template_create_window_desc( - WDP_AUTO, // window position - "template create window", // const char* ini_key - 456, 100, // window size - WC_CREATE_TEMPLATE, // window class - WC_NONE, // parent window class - WDF_CONSTRUCTION, // window flags - _widgets, lengthof(_widgets) // widgets + num widgets + WDP_AUTO, // window position + "template create window", // const char* ini_key + 456, 100, // window size + WC_CREATE_TEMPLATE, // window class + WC_TEMPLATEGUI_MAIN, // parent window class + WDF_CONSTRUCTION, // window flags + _widgets, lengthof(_widgets) // widgets + num widgets ); static void TrainDepotMoveVehicle(const Vehicle *wagon, VehicleID sel, const Vehicle *head) @@ -107,7 +119,8 @@ static void TrainDepotMoveVehicle(const Vehicle *wagon, VehicleID sel, const Veh if (wagon == v) return; - DoCommandP(v->tile, v->index | (_ctrl_pressed ? 1 : 0) << 20 | 1 << 21, wagon == NULL ? INVALID_VEHICLE : wagon->index, CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_MOVE_VEHICLE), CcVirtualTrainWaggonsMoved); + DoCommandP(v->tile, v->index | ((_ctrl_pressed ? 1 : 0) << 20) | (1 << 21) , wagon == NULL ? INVALID_VEHICLE : wagon->index, + CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_MOVE_VEHICLE), CcVirtualTrainWaggonsMoved); } class TemplateCreateWindow : public Window { @@ -118,7 +131,7 @@ private: Train* virtual_train; bool editMode; bool *noticeParent; - bool *createWindowOpen; /// used to notify main window of progress (dummy way of disabling 'delete' while editing a template) + bool *createWindowOpen; /// used to notify main window of progress (dummy way of disabling 'delete' while editing a template) bool virtualTrainChangedNotice; VehicleID sel; VehicleID vehicle_over; @@ -142,8 +155,7 @@ public: virtualTrainChangedNotice = false; this->editTemplate = to_edit; - if (to_edit) editMode = true; - else editMode = false; + editMode = (to_edit != NULL); this->sel = INVALID_VEHICLE; this->vehicle_over = INVALID_VEHICLE; @@ -157,9 +169,9 @@ public: ~TemplateCreateWindow() { - if (virtual_train != nullptr) { + if (virtual_train != NULL) { DoCommandP(0, virtual_train->index, 0, CMD_DELETE_VIRTUAL_TRAIN); - virtual_train = nullptr; + virtual_train = NULL; } SetWindowClassesDirty(WC_TRAINS_LIST); @@ -167,12 +179,11 @@ public: /* more cleanup */ *createWindowOpen = false; DeleteWindowById(WC_BUILD_VIRTUAL_TRAIN, this->window_number); - } void SetVirtualTrain(Train* const train) { - if (virtual_train != nullptr) { + if (virtual_train != NULL) { DoCommandP(0, virtual_train->index, 0, CMD_DELETE_VIRTUAL_TRAIN); } @@ -210,19 +221,18 @@ public: this->SetWidgetDirty(TCW_CLONE); this->ToggleWidgetLoweredState(TCW_CLONE); if (this->IsWidgetLowered(TCW_CLONE)) { - static const CursorID clone_icon = SPR_CURSOR_CLONE_TRAIN; - SetObjectToPlaceWnd(clone_icon, PAL_NONE, HT_VEHICLE, this); + SetObjectToPlaceWnd(SPR_CURSOR_CLONE_TRAIN, PAL_NONE, HT_VEHICLE, this); } else { ResetObjectToPlace(); } break; } case TCW_OK: { - uint32 templateIndex = (editTemplate != nullptr) ? editTemplate->index : INVALID_VEHICLE; - - if (virtual_train != nullptr) { + uint32 templateIndex = (editTemplate != NULL) ? editTemplate->index : INVALID_VEHICLE; + + if (virtual_train != NULL) { DoCommandP(0, templateIndex, virtual_train->index, CMD_REPLACE_TEMPLATE_VEHICLE); - virtual_train = nullptr; + virtual_train = NULL; } else if (templateIndex != INVALID_VEHICLE) { DoCommandP(0, templateIndex, 0, CMD_DELETE_TEMPLATE_VEHICLE); } @@ -243,9 +253,9 @@ public: virtual bool OnVehicleSelect(const Vehicle *v) { // throw away the current virtual train - if (virtual_train != nullptr) { + if (virtual_train != NULL) { DoCommandP(0, virtual_train->index, 0, CMD_DELETE_VIRTUAL_TRAIN); - virtual_train = nullptr; + virtual_train = NULL; } // create a new one @@ -261,8 +271,8 @@ public: { switch(widget) { case TCW_NEW_TMPL_PANEL: { - if ( this->virtual_train ) { - DrawTrainImage(virtual_train, r.left+TRAIN_FRONT_SPACE, r.right-25, r.top+2, this->sel, EIT_PURCHASE, this->hscroll->GetPosition(), this->vehicle_over); + if (this->virtual_train) { + DrawTrainImage(virtual_train, r.left+TRAIN_FRONT_SPACE, r.right - 25, r.top + 2, this->sel, EIT_PURCHASE, this->hscroll->GetPosition(), this->vehicle_over); SetDParam(0, CeilDiv(virtual_train->gcache.cached_total_length * 10, TILE_SIZE)); SetDParam(1, 1); DrawString(r.left, r.right, r.top, STR_TINY_BLACK_DECIMAL, TC_BLACK, SA_RIGHT); @@ -270,7 +280,7 @@ public: break; } case TCW_INFO_PANEL: { - if ( this->virtual_train ) { + if (this->virtual_train) { DrawPixelInfo tmp_dpi, *old_dpi; if (!FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left, r.bottom - r.top)) break; @@ -287,16 +297,16 @@ public: DrawString(8, r.right, 4 - this->vscroll->GetPosition(), STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE); /* Draw cargo summary */ CargoArray cargo_caps; - for ( const Train *tmp=this->virtual_train; tmp; tmp=tmp->Next() ) + for (const Train *tmp = this->virtual_train; tmp != NULL; tmp = tmp->Next()) { cargo_caps[tmp->cargo_type] += tmp->cargo_cap; + } int y = 30 - this->vscroll->GetPosition(); for (CargoID i = 0; i < NUM_CARGO; ++i) { - if ( cargo_caps[i] > 0 ) { + if (cargo_caps[i] > 0) { SetDParam(0, i); SetDParam(1, cargo_caps[i]); - SetDParam(2, _settings_game.vehicle.freight_trains); DrawString(8, r.right, y, STR_TMPL_CARGO_SUMMARY, TC_LIGHT_BLUE, SA_LEFT); - y += this->line_height/3; + y += this->line_height / 3; } } @@ -308,6 +318,7 @@ public: break; } } + virtual void OnTick() { if (virtualTrainChangedNotice) { @@ -315,6 +326,7 @@ public: virtualTrainChangedNotice = false; } } + virtual void OnDragDrop(Point pt, int widget) { switch (widget) { @@ -344,10 +356,11 @@ public: Train* train_to_delete = Train::Get(this->sel); - if (virtual_train == train_to_delete) - virtual_train = (_ctrl_pressed) ? nullptr : virtual_train->GetNextUnit(); + if (virtual_train == train_to_delete) { + virtual_train = (_ctrl_pressed) ? NULL : virtual_train->GetNextUnit(); + } - DoCommandP(0, this->sel | sell_cmd << 20 | 1 << 21, 0, GetCmdSellVeh(VEH_TRAIN)); + DoCommandP(0, this->sel | (sell_cmd << 20) | (1 << 21), 0, GetCmdSellVeh(VEH_TRAIN)); this->sel = INVALID_VEHICLE; @@ -357,6 +370,7 @@ public: default: this->sel = INVALID_VEHICLE; this->SetDirty(); + break; } _cursor.vehchain = false; this->sel = INVALID_VEHICLE; @@ -408,15 +422,15 @@ public: uint height = 30; CargoArray cargo_caps; - if (virtual_train != nullptr) { - for (Train *train = virtual_train; train != nullptr; train = train->Next()) { + if (virtual_train != NULL) { + for (Train *train = virtual_train; train != NULL; train = train->Next()) { width += train->GetDisplayImageWidth(); cargo_caps[train->cargo_type] += train->cargo_cap; } for (CargoID i = 0; i < NUM_CARGO; ++i) { - if ( cargo_caps[i] > 0 ) { - height += this->line_height/3; + if (cargo_caps[i] > 0) { + height += this->line_height / 3; } } } @@ -429,6 +443,7 @@ public: this->DrawWidgets(); } + struct GetDepotVehiclePtData { const Vehicle *head; const Vehicle *wagon; @@ -449,7 +464,7 @@ public: const NWidgetCore *matrix_widget = this->GetWidget(TCW_NEW_TMPL_PANEL); /* In case of RTL the widgets are swapped as a whole */ if (_current_text_dir == TD_RTL) x = matrix_widget->current_x - x; - + x -= TRAIN_FRONT_SPACE; uint xm = x; @@ -461,7 +476,6 @@ public: d->head = d->wagon = v; if (xm <= this->header_width) { - if (wagon) return MODE_ERROR; return MODE_SHOW_VEHICLE; @@ -494,7 +508,7 @@ public: if (sel != INVALID_VEHICLE) { this->sel = INVALID_VEHICLE; - TrainDepotMoveVehicle(v, sel, gdvp.head); + TrainDepotMoveVehicle(v, sel, gdvp.head); } else if (v != NULL) { int image = v->GetImage(_current_text_dir == TD_RTL ? DIR_E : DIR_W, EIT_PURCHASE); SetObjectToPlaceWnd(image, GetVehiclePalette(v), HT_DRAG, this); @@ -515,7 +529,7 @@ public: void ShowTemplateCreateWindow(TemplateVehicle *to_edit, bool *noticeParent, bool *createWindowOpen, int step_h) { - if ( BringWindowToFrontById(WC_CREATE_TEMPLATE, VEH_TRAIN) != NULL ) return; + if (BringWindowToFrontById(WC_CREATE_TEMPLATE, VEH_TRAIN) != NULL) return; new TemplateCreateWindow(&_template_create_window_desc, to_edit, noticeParent, createWindowOpen, step_h); } @@ -546,4 +560,4 @@ void CcDeleteVirtualTrain(const CommandCost &result, TileIndex tile, uint32 p1, { VehicleID virtual_train_id = p2; DoCommandP(0, virtual_train_id, 0, CMD_DELETE_VIRTUAL_TRAIN); -} \ No newline at end of file +} diff --git a/src/tbtr_template_gui_create.h b/src/tbtr_template_gui_create.h index 4ab054a60c..d95cf53bdf 100644 --- a/src/tbtr_template_gui_create.h +++ b/src/tbtr_template_gui_create.h @@ -1,4 +1,13 @@ -// template creation gui +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file tbtr_template_gui_create.h Template-based train replacement: template creation GUI header. */ #ifndef TEMPLATE_GUI_CREATE #define TEMPLATE_GUI_CREATE diff --git a/src/tbtr_template_gui_create_virtualtrain.cpp b/src/tbtr_template_gui_create_virtualtrain.cpp index 63612ddb6e..de3f537327 100644 --- a/src/tbtr_template_gui_create_virtualtrain.cpp +++ b/src/tbtr_template_gui_create_virtualtrain.cpp @@ -1,4 +1,4 @@ -/* $Id: build_vehicle_gui.cpp 23792 2012-01-12 19:23:00Z yexo $ */ +/* $Id$ */ /* * This file is part of OpenTTD. @@ -7,7 +7,7 @@ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . */ -/** @file build_vehicle_gui.cpp GUI for building vehicles. */ +/** @file tbtr_template_gui_create_virtualtrain.cpp Template-based train replacement: template creation vehicle build GUI. */ #include "stdafx.h" #include "engine_base.h" @@ -30,14 +30,14 @@ #include "engine_gui.h" #include "cargotype.h" #include "core/geometry_func.hpp" +#include "vehicle_gui.h" +#include "tbtr_template_gui_create_virtualtrain.h" #include "widgets/build_vehicle_widget.h" #include "table/strings.h" -#include "tbtr_template_gui_create_virtualtrain.h" - -#include "vehicle_gui.h" +#include "safeguards.h" static const NWidgetPart _nested_build_vehicle_widgets[] = { NWidget(NWID_HORIZONTAL), @@ -425,13 +425,13 @@ struct BuildVirtualTrainWindow : Window { byte cargo_filter_criteria; ///< Selected cargo filter int details_height; ///< Minimal needed height of the details panels (found so far). Scrollbar *vscroll; - Train **virtual_train; ///< the virtual train that is currently being created + Train **virtual_train; ///< the virtual train that is currently being created bool *noticeParent; BuildVirtualTrainWindow(WindowDesc *desc, Train **vt, bool *notice) : Window(desc) { this->vehicle_type = VEH_TRAIN; - this->window_number = 0;//tile == INVALID_TILE ? (int)type : tile; + this->window_number = 0; this->sel_engine = INVALID_ENGINE; @@ -688,6 +688,7 @@ struct BuildVirtualTrainWindow : Window { case WID_BV_CARGO_FILTER_DROPDOWN: SetDParam(0, this->cargo_filter_texts[this->cargo_filter_criteria]); + break; } } @@ -717,7 +718,9 @@ struct BuildVirtualTrainWindow : Window { { switch (widget) { case WID_BV_LIST: - DrawEngineList(this->vehicle_type, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, &this->eng_list, this->vscroll->GetPosition(), min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->eng_list.Length()), this->sel_engine, false, DEFAULT_GROUP); + DrawEngineList(this->vehicle_type, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, + &this->eng_list, this->vscroll->GetPosition(), min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), + this->eng_list.Length()), this->sel_engine, false, DEFAULT_GROUP); break; case WID_BV_SORT_ASCENDING_DESCENDING: @@ -795,7 +798,7 @@ struct BuildVirtualTrainWindow : Window { } else { VehicleID target = (*(this->virtual_train))->GetLastUnit()->index; - DoCommandP(0, (1<<21) | toadd->index, target, CMD_MOVE_RAIL_VEHICLE); + DoCommandP(0, (1 << 21) | toadd->index, target, CMD_MOVE_RAIL_VEHICLE); } *noticeParent = true; } @@ -814,13 +817,13 @@ void CcAddVirtualEngine(const CommandCost &result, TileIndex tile, uint32 p1, ui } static WindowDesc _build_vehicle_desc( - WDP_AUTO, // window position - "template create virtual train",// const char* ini_key - 240, 268, // window size - WC_BUILD_VIRTUAL_TRAIN, // window class - WC_CREATE_TEMPLATE, // parent window class - WDF_CONSTRUCTION, // window flags - _nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets) // widgets + num widgets + WDP_AUTO, // window position + "template create virtual train", // const char* ini_key + 240, 268, // window size + WC_BUILD_VIRTUAL_TRAIN, // window class + WC_CREATE_TEMPLATE, // parent window class + WDF_CONSTRUCTION, // window flags + _nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets) // widgets + num widgets ); void ShowBuildVirtualTrainWindow(Train **vt, bool *noticeParent) diff --git a/src/tbtr_template_gui_create_virtualtrain.h b/src/tbtr_template_gui_create_virtualtrain.h index d454f74069..ee0b4123c3 100644 --- a/src/tbtr_template_gui_create_virtualtrain.h +++ b/src/tbtr_template_gui_create_virtualtrain.h @@ -1,3 +1,14 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file tbtr_template_gui_create_virtualtrain.cpp Template-based train replacement: template creation vehicle build GUI header. */ + #ifndef BUILD_VIRTUAL_TRAIN_GUI #define BUILD_VIRTUAL_TRAIN_GUI diff --git a/src/tbtr_template_gui_main.cpp b/src/tbtr_template_gui_main.cpp index 82b6c18029..4d90390502 100644 --- a/src/tbtr_template_gui_main.cpp +++ b/src/tbtr_template_gui_main.cpp @@ -1,10 +1,13 @@ -// mygui.c +/* $Id$ */ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ -//#include "tbtr_mygui.h" -#include -#include - +/** @file tbtr_template_gui_main.cpp Template-based train replacement: main GUI. */ #include "stdafx.h" #include "command_func.h" @@ -47,7 +50,11 @@ #include "tbtr_template_gui_main.h" #include "tbtr_template_gui_create.h" #include "tbtr_template_vehicle.h" -//#include "tbtr_template_vehicle_func.h" + +#include +#include + +#include "safeguards.h" typedef GUIList GUIGroupList; @@ -168,7 +175,7 @@ static WindowDesc _replace_rail_vehicle_desc( "template replace window", 456, 156, WC_TEMPLATEGUI_MAIN, - WC_NONE, // parent window class + WC_NONE, // parent window class WDF_CONSTRUCTION, _widgets, lengthof(_widgets) ); @@ -176,7 +183,7 @@ static WindowDesc _replace_rail_vehicle_desc( class TemplateReplaceWindow : public Window { private: - GUIGroupList groups; ///< List of groups + GUIGroupList groups; ///< List of groups byte unitnumber_digits; SmallVector indents; ///< Indentation levels @@ -207,7 +214,7 @@ public: this->unitnumber_digits = dig; this->sel_railtype = RAILTYPE_BEGIN; - this->details_height = 10 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + this->details_height = 10 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; this->line_height = step_h; @@ -311,7 +318,7 @@ public: this->BuildGroupList(_local_company); - if ( templateNotice ) { + if (templateNotice) { BuildTemplateGuiList(&this->templates, vscroll[1], _local_company, this->sel_railtype); templateNotice = false; this->SetDirty(); @@ -333,14 +340,14 @@ public: short count_columns = 0; short max_columns = 2; - for ( ; tmp; tmp=tmp->Next()) { + for (; tmp != NULL; tmp = tmp->Next()) { cargo_caps[tmp->cargo_type] += tmp->cargo_cap; } for (CargoID i = 0; i < NUM_CARGO; ++i) { - if ( cargo_caps[i] > 0 ) { + if (cargo_caps[i] > 0) { if (count_columns % max_columns == 0) { - height += this->line_height/3; + height += this->line_height / 3; } ++count_columns; @@ -356,7 +363,7 @@ public: virtual void OnClick(Point pt, int widget, int click_count) { - if ( this->editInProgress ) return; + if (this->editInProgress) return; switch (widget) { case TRW_WIDGET_TMPL_BUTTONS_CONFIGTMPL_REUSE: { @@ -424,28 +431,26 @@ public: ShowDropDownList(this, GetRailTypeDropDownList(true), sel_railtype, TRW_WIDGET_TRAIN_RAILTYPE_DROPDOWN); break; case TRW_WIDGET_TOP_MATRIX: { - uint16 newindex = (uint16)((pt.y - this->nested_array[TRW_WIDGET_TOP_MATRIX]->pos_y) / (this->line_height/2) ) + this->vscroll[0]->GetPosition(); - if ( newindex == this->selected_group_index || newindex >= this->groups.Length() ) { + uint16 newindex = (uint16)((pt.y - this->nested_array[TRW_WIDGET_TOP_MATRIX]->pos_y) / (this->line_height / 2) ) + this->vscroll[0]->GetPosition(); + if (newindex == this->selected_group_index || newindex >= this->groups.Length()) { this->selected_group_index = -1; - } - else if ((newindex >= 0) && (newindex < this->groups.Length())) { + } else if (newindex < this->groups.Length()) { this->selected_group_index = newindex; } break; } case TRW_WIDGET_BOTTOM_MATRIX: { uint16 newindex = (uint16)((pt.y - this->nested_array[TRW_WIDGET_BOTTOM_MATRIX]->pos_y) / this->line_height) + this->vscroll[1]->GetPosition(); - if ( newindex == this->selected_template_index || newindex >= templates.Length() ) { + if (newindex == this->selected_template_index || newindex >= templates.Length()) { this->selected_template_index = -1; - } - else if ((newindex >= 0) && (newindex < templates.Length())) { + } else if (newindex < templates.Length()) { this->selected_template_index = newindex; } break; } case TRW_WIDGET_START: { if ((this->selected_template_index >= 0) && (this->selected_template_index < (short)this->templates.Length()) && - (this->selected_group_index >= 0) && (this->selected_group_index < (short)this->groups.Length())) { + (this->selected_group_index >= 0) && (this->selected_group_index < (short)this->groups.Length())) { uint32 tv_index = ((this->templates)[selected_template_index])->index; int current_group_index = (this->groups)[this->selected_group_index]->index; @@ -454,8 +459,9 @@ public: break; } case TRW_WIDGET_STOP: - if ((this->selected_group_index < 0) || (this->selected_group_index >= (short)this->groups.Length())) + if ((this->selected_group_index < 0) || (this->selected_group_index >= (short)this->groups.Length())) { return; + } int current_group_index = (this->groups)[this->selected_group_index]->index; @@ -481,7 +487,7 @@ public: virtual void OnDropdownSelect(int widget, int index) { - RailType temp = (RailType)index; + RailType temp = (RailType) index; if (temp == this->sel_railtype) return; // we didn't select a new one. No need to change anything this->sel_railtype = temp; /* Reset scrollbar positions */ @@ -508,7 +514,7 @@ public: virtual void OnTick() { - if ( templateNotice ) { + if (templateNotice) { BuildTemplateGuiList(&this->templates, this->vscroll[1], this->owner, this->sel_railtype); this->SetDirty(); templateNotice = false; @@ -527,12 +533,13 @@ public: short FindTemplateIndexForGroup(short gid) const { TemplateReplacement *tr = GetTemplateReplacementByGroupID(gid); - if ( !tr ) - return -1; + if (!tr) return -1; - for ( uint32 i=0; itemplates.Length(); ++i ) - if ( templates[i]->index == tr->sel_template ) + for (uint32 i = 0; i < this->templates.Length(); ++i) { + if (templates[i]->index == tr->sel_template) { return i; + } + } return -1; } @@ -604,47 +611,48 @@ public: int max = min(this->vscroll[0]->GetPosition() + this->vscroll[0]->GetCapacity(), this->groups.Length()); /* Then treat all groups defined by/for the current company */ - for ( int i=this->vscroll[0]->GetPosition(); ivscroll[0]->GetPosition(); i < max; ++i) { const Group *g = (this->groups)[i]; short g_id = g->index; /* Fill the background of the current cell in a darker tone for the currently selected template */ - if ( this->selected_group_index == i ) { - GfxFillRect(left, y, right, y+(this->line_height)/2, _colour_gradient[COLOUR_GREY][3]); + if (this->selected_group_index == i) { + GfxFillRect(left, y, right, y+(this->line_height) / 2, _colour_gradient[COLOUR_GREY][3]); } SetDParam(0, g_id); StringID str = STR_GROUP_NAME; - DrawString(left+30+ this->indents[i] * 10, right, y+2, str, TC_BLACK); + DrawString(left + 30 + this->indents[i] * 10, right, y + 2, str, TC_BLACK); /* Draw the template in use for this group, if there is one */ short template_in_use = FindTemplateIndexForGroup(g_id); - if ( template_in_use >= 0 ) { + if (template_in_use >= 0) { SetDParam(0, template_in_use); - DrawString ( left, right, y+2, STR_TMPL_GROUP_USES_TEMPLATE, TC_BLACK, SA_HOR_CENTER); - } - /* If there isn't a template applied from the current group, check if there is one for another rail type */ - else if ( GetTemplateReplacementByGroupID(g_id) ) { - DrawString ( left, right, y+2, STR_TMPL_TMPLRPL_EX_DIFF_RAILTYPE, TC_SILVER, SA_HOR_CENTER); + DrawString (left, right, y + 2, STR_TMPL_GROUP_USES_TEMPLATE, TC_BLACK, SA_HOR_CENTER); + } else if (GetTemplateReplacementByGroupID(g_id)) { /* If there isn't a template applied from the current group, check if there is one for another rail type */ + DrawString (left, right, y + 2, STR_TMPL_TMPLRPL_EX_DIFF_RAILTYPE, TC_SILVER, SA_HOR_CENTER); } /* Draw the number of trains that still need to be treated by the currently selected template replacement */ TemplateReplacement *tr = GetTemplateReplacementByGroupID(g_id); - if ( tr ) { + if (tr) { TemplateVehicle *tv = TemplateVehicle::Get(tr->sel_template); int num_trains = NumTrainsNeedTemplateReplacement(g_id, tv); // Draw text TextColour color = TC_GREY; - if ( num_trains ) color = TC_BLACK; - DrawString(left, right-16, y+2, STR_TMPL_NUM_TRAINS_NEED_RPL, color, SA_RIGHT); + if (num_trains) color = TC_BLACK; + DrawString(left, right - 16, y + 2, STR_TMPL_NUM_TRAINS_NEED_RPL, color, SA_RIGHT); // Draw number - if ( num_trains ) color = TC_ORANGE; - else color = TC_GREY; + if (num_trains ) { + color = TC_ORANGE; + } else { + color = TC_GREY; + } SetDParam(0, num_trains); - DrawString(left, right-4, y+2, STR_JUST_INT, color, SA_RIGHT); + DrawString(left, right - 4, y + 2, STR_JUST_INT, color, SA_RIGHT); } - y+=line_height / 2; + y += line_height / 2; } } @@ -658,52 +666,51 @@ public: uint max = min(draw_vscroll->GetPosition() + draw_vscroll->GetCapacity(), this->templates.Length()); const TemplateVehicle *v; - for ( uint i = draw_vscroll->GetPosition(); i < max; ++i) { - + for (uint i = draw_vscroll->GetPosition(); i < max; ++i) { v = (this->templates)[i]; /* Fill the background of the current cell in a darker tone for the currently selected template */ - if ( this->selected_template_index == (int32)i ) { - GfxFillRect(left, y, right, y+this->line_height, _colour_gradient[COLOUR_GREY][3]); + if (this->selected_template_index == (int32) i) { + GfxFillRect(left, y, right, y + this->line_height, _colour_gradient[COLOUR_GREY][3]); } /* Draw a notification string for chains that are not runnable */ - if ( v->IsFreeWagonChain() ) { - DrawString(left, right-2, y+line_height-FONT_HEIGHT_SMALL-WD_FRAMERECT_BOTTOM - 2, STR_TMPL_WARNING_FREE_WAGON, TC_RED, SA_RIGHT); + if (v->IsFreeWagonChain()) { + DrawString(left, right - 2, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_WARNING_FREE_WAGON, TC_RED, SA_RIGHT); } /* Draw the template's length in tile-units */ SetDParam(0, v->GetRealLength()); SetDParam(1, 1); - DrawString(left, right-4, y+2, STR_TINY_BLACK_DECIMAL, TC_BLACK, SA_RIGHT); + DrawString(left, right - 4, y + 2, STR_TINY_BLACK_DECIMAL, TC_BLACK, SA_RIGHT); /* Draw the template */ - DrawTemplate(v, left+50, right, y); + DrawTemplate(v, left + 50, right, y); /* Buying cost */ SetDParam(0, CalculateOverallTemplateCost(v)); - DrawString(left+35, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_TEMPLATE_OVR_VALUE_notinyfont, TC_BLUE, SA_LEFT); + DrawString(left + 35, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_TEMPLATE_OVR_VALUE_notinyfont, TC_BLUE, SA_LEFT); /* Index of current template vehicle in the list of all templates for its company */ SetDParam(0, i); - DrawString(left+5, left+25, y + 2, STR_BLACK_INT, TC_BLACK, SA_RIGHT); + DrawString(left + 5, left + 25, y + 2, STR_BLACK_INT, TC_BLACK, SA_RIGHT); /* Draw whether the current template is in use by any group */ - if ( v->NumGroupsUsingTemplate() > 0 ) { - DrawString(left+35, right, y + line_height - FONT_HEIGHT_SMALL * 2 - 4 - WD_FRAMERECT_BOTTOM - 2, STR_TMP_TEMPLATE_IN_USE, TC_GREEN, SA_LEFT); + if (v->NumGroupsUsingTemplate() > 0) { + DrawString(left + 35, right, y + line_height - FONT_HEIGHT_SMALL * 2 - 4 - WD_FRAMERECT_BOTTOM - 2, STR_TMP_TEMPLATE_IN_USE, TC_GREEN, SA_LEFT); } /* Draw information about template configuration settings */ TextColour color; - if ( v->IsSetReuseDepotVehicles() ) color = TC_LIGHT_BLUE; - else color = TC_GREY; - DrawString(left+300, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_CONFIG_USEDEPOT, color, SA_LEFT); - if ( v->IsSetKeepRemainingVehicles() ) color = TC_LIGHT_BLUE; - else color = TC_GREY; - DrawString(left+400, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_CONFIG_KEEPREMAINDERS, color, SA_LEFT); - if ( v->IsSetRefitAsTemplate() ) color = TC_LIGHT_BLUE; - else color = TC_GREY; - DrawString(left+500, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_CONFIG_REFIT, color, SA_LEFT); + + color = v->IsSetReuseDepotVehicles() ? TC_LIGHT_BLUE : TC_GREY; + DrawString(left + 300, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_CONFIG_USEDEPOT, color, SA_LEFT); + + color = v->IsSetKeepRemainingVehicles() ? TC_LIGHT_BLUE : TC_GREY; + DrawString(left + 400, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_CONFIG_KEEPREMAINDERS, color, SA_LEFT); + + color = v->IsSetRefitAsTemplate() ? TC_LIGHT_BLUE : TC_GREY; + DrawString(left + 500, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_CONFIG_REFIT, color, SA_LEFT); y += line_height; } @@ -711,13 +718,15 @@ public: void DrawTemplateInfo(int line_height, const Rect &r) const { - if ((this->selected_template_index < 0) || (this->selected_template_index >= (short)this->templates.Length())) + if ((this->selected_template_index < 0) || (this->selected_template_index >= (short)this->templates.Length())) { return; + } DrawPixelInfo tmp_dpi, *old_dpi; - if (!FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left, r.bottom - r.top)) + if (!FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left, r.bottom - r.top)) { return; + } old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; @@ -738,20 +747,21 @@ public: short max_columns = 2; CargoArray cargo_caps; - for ( ; tmp; tmp=tmp->Next() ) + for (; tmp != NULL; tmp = tmp->Next()) { cargo_caps[tmp->cargo_type] += tmp->cargo_cap; + } int x = left; for (CargoID i = 0; i < NUM_CARGO; ++i) { - if ( cargo_caps[i] > 0 ) { + if (cargo_caps[i] > 0) { count_columns++; SetDParam(0, i); SetDParam(1, cargo_caps[i]); SetDParam(2, _settings_game.vehicle.freight_trains); DrawString(x, r.right, top, FreightWagonMult(i) > 1 ? STR_TMPL_CARGO_SUMMARY_MULTI : STR_TMPL_CARGO_SUMMARY, TC_LIGHT_BLUE, SA_LEFT); x += 250; - if ( count_columns % max_columns == 0 ) { + if (count_columns % max_columns == 0) { x = left; - top += this->line_height/3; + top += this->line_height / 3; } } } @@ -764,4 +774,3 @@ void ShowTemplateReplaceWindow(byte dig, int step_h) { new TemplateReplaceWindow(&_replace_rail_vehicle_desc, dig, step_h); } - diff --git a/src/tbtr_template_gui_main.h b/src/tbtr_template_gui_main.h index 69e68d56d8..cae44e200f 100644 --- a/src/tbtr_template_gui_main.h +++ b/src/tbtr_template_gui_main.h @@ -1,4 +1,13 @@ -// _template_gui_main.h +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file tbtr_template_gui_main.h Template-based train replacement: main GUI header. */ #ifndef TEMPLATE_GUI_H #define TEMPLATE_GUI_H diff --git a/src/tbtr_template_gui_replaceall.cpp b/src/tbtr_template_gui_replaceall.cpp index 36d4396582..445ded53ef 100644 --- a/src/tbtr_template_gui_replaceall.cpp +++ b/src/tbtr_template_gui_replaceall.cpp @@ -1,9 +1,38 @@ -// replace all gui impl +/* $Id$ */ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file tbtr_template_gui_replaceall.cpp Template-based train replacement: replace all GUI. */ + +#include "stdafx.h" +#include "window_gui.h" +#include "window_func.h" + +#include "company_func.h" +#include "engine_base.h" +#include "engine_func.h" +#include "engine_gui.h" +#include "train.h" +#include "strings_func.h" +#include "vehicle_base.h" +#include "vehicle_func.h" + +#include "tbtr_template_vehicle.h" +#include "tbtr_template_vehicle_func.h" + +#include "core/math_func.hpp" +#include "table/strings.h" #include "tbtr_template_gui_replaceall.h" #include +#include "safeguards.h" + /* * A wrapper which contains a virtual train and additional info of the template vehicle it is replacing * We will restore this additional info when creating a new template from the changed virtual train @@ -15,9 +44,9 @@ struct VirtTrainInfo { // additional info from the template VehicleID original_index; - bool reuse_depot_vehicles, - keep_remaining_vehicles, - refit_as_template; + bool reuse_depot_vehicles; + bool keep_remaining_vehicles; + bool refit_as_template; CargoID cargo_type; byte cargo_subtype; @@ -133,19 +162,19 @@ static int CDECL TrainEnginesThenWagonsSorter(const EngineID *a, const EngineID class TemplateReplacementReplaceAllWindow : public Window { private: uint16 line_height; - Scrollbar *vscroll_tl, - *vscroll_tr, - *vscroll_bo; - GUIEngineList *engines_left, - *engines_right; - short selected_left, - selected_right; + Scrollbar *vscroll_tl; + Scrollbar *vscroll_tr; + Scrollbar *vscroll_bo; + GUIEngineList *engines_left; + GUIEngineList *engines_right; + short selected_left; + short selected_right; VirtTrainList *virtualTrains; public: TemplateReplacementReplaceAllWindow(WindowDesc *wdesc) : Window(wdesc) { - this->CreateNestedTree(wdesc != nullptr); + this->CreateNestedTree(wdesc != NULL); this->vscroll_tl = this->GetScrollbar(RPLALL_GUI_SCROLL_TL); this->vscroll_tr = this->GetScrollbar(RPLALL_GUI_SCROLL_TR); @@ -172,14 +201,15 @@ public: ~TemplateReplacementReplaceAllWindow() { - for ( uint i=0; ivirtualTrains->Length(); ++i ) + for (uint i = 0; ivirtualTrains->Length(); ++i) { delete (*this->virtualTrains)[i]->vt; + } SetWindowClassesDirty(WC_TEMPLATEGUI_MAIN); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { - switch ( widget ) { + switch (widget) { case RPLALL_GUI_MATRIX_TOPLEFT: case RPLALL_GUI_MATRIX_TOPRIGHT: case RPLALL_GUI_MATRIX_BOTTOM: { @@ -235,19 +265,21 @@ public: switch(widget) { case RPLALL_GUI_MATRIX_TOPLEFT: { uint16 newindex = (uint16)((pt.y - this->nested_array[RPLALL_GUI_MATRIX_TOPLEFT]->pos_y) / this->line_height) + this->vscroll_tl->GetPosition(); - if ( newindex >= this->engines_left->Length() || newindex==this->selected_left ) + if (newindex >= this->engines_left->Length() || newindex == this->selected_left) { this->selected_left = -1; - else + } else { this->selected_left = newindex; + } this->SetDirty(); break; } case RPLALL_GUI_MATRIX_TOPRIGHT: { uint16 newindex = (uint16)((pt.y - this->nested_array[RPLALL_GUI_MATRIX_TOPRIGHT]->pos_y) / this->line_height) + this->vscroll_tr->GetPosition(); - if ( newindex > this->engines_right->Length() || newindex==this->selected_right ) + if (newindex > this->engines_right->Length() || newindex==this->selected_right) { this->selected_right = -1; - else + } else { this->selected_right = newindex; + } this->SetDirty(); break; } @@ -257,12 +289,13 @@ public: } case RPLALL_GUI_BUTTON_APPLY: { // check if we actually did anything so far, if not, applying is forbidden - if ( this->virtualTrains->Length() == 0 ) + if (this->virtualTrains->Length() == 0) { return; + } // first delete all current templates this->DeleteAllTemplateTrains(); // then build a new list from the current virtual trains - for ( uint i=0; ivirtualTrains->Length(); ++i ) { + for (uint i = 0; i < this->virtualTrains->Length(); ++i) { // the relevant info struct VirtTrainInfo *vti = (*this->virtualTrains)[i]; // setup template from contained train @@ -276,8 +309,9 @@ public: tv->cargo_subtype = vti->cargo_subtype; // use the original_index information to repoint the relevant TemplateReplacement if existing TemplateReplacement *tr = GetTemplateReplacementByTemplateID(vti->original_index); - if ( tr ) + if (tr) { tr->sel_template = tv->index; + } } // then close this window and return to parent delete this; @@ -294,10 +328,11 @@ public: { const TemplateVehicle *tv; FOR_ALL_TEMPLATES(tv) { - if ( tv->Prev() || tv->owner != _local_company ) continue; - for ( const TemplateVehicle *tmp=tv; tmp; tmp=tmp->GetNextUnit() ) { - if ( tmp->engine_type == eid ) + if (tv->Prev() || tv->owner != _local_company) continue; + for (const TemplateVehicle *tmp = tv; tmp != NULL; tmp = tmp->GetNextUnit()) { + if (tmp->engine_type == eid) { return true; + } } } return false; @@ -309,17 +344,17 @@ public: TemplateVehicle *tv; FOR_ALL_TEMPLATES(tv) { - if ( !tv->Prev() && tv->owner==this->owner ) { + if (!tv->Prev() && tv->owner == this->owner) { // setup template train Train *newtrain = VirtualTrainFromTemplateVehicle(tv); VirtTrainInfo *vti = new VirtTrainInfo(newtrain); // store template specific stuff - vti->original_index = tv->index; - vti->reuse_depot_vehicles = tv->reuse_depot_vehicles; - vti->keep_remaining_vehicles = tv->keep_remaining_vehicles; - vti->refit_as_template = tv->refit_as_template; - vti->cargo_type = tv->cargo_type; - vti->cargo_subtype = tv->cargo_subtype; + vti->original_index = tv->index; + vti->reuse_depot_vehicles = tv->reuse_depot_vehicles; + vti->keep_remaining_vehicles = tv->keep_remaining_vehicles; + vti->refit_as_template = tv->refit_as_template; + vti->cargo_type = tv->cargo_type; + vti->cargo_subtype = tv->cargo_subtype; // add new info struct *this->virtualTrains->Append() = vti; } @@ -333,8 +368,9 @@ public: TemplateVehicle *tv, *tmp; FOR_ALL_TEMPLATES(tv) { tmp = tv; - if ( tmp->Prev()==0 && tmp->owner==this->owner ) + if (tmp->Prev() == NULL && tmp->owner == this->owner) { delete tmp; + } } } @@ -350,7 +386,7 @@ public: EngineID eid = e->index; const RailVehicleInfo*rvi = &e->u.rail; - if ( !HasTemplateWithEngine(eid) ) continue; + if (!HasTemplateWithEngine(eid)) continue; *this->engines_left->Append() = eid; @@ -366,11 +402,13 @@ public: bool VirtualTrainHasEngineID(EngineID eid) { - for ( uint i=0; ivirtualTrains->Length(); ++i ) { + for (uint i = 0; i < this->virtualTrains->Length(); ++i) { const Train *tmp = (*this->virtualTrains)[i]->vt; - for ( ; tmp; tmp=tmp->Next() ) - if ( tmp->engine_type == eid ) + for (; tmp != NULL; tmp = tmp->Next()) { + if (tmp->engine_type == eid) { return true; + } + } } return false; } @@ -378,44 +416,43 @@ public: // after 'replace all' we need to replace the currently used templates as well void RebuildIncludedTemplateList() { // first remove all engine ids - for ( uint i=0; iengines_left->Length(); ++i ) { + for (uint i = 0; i < this->engines_left->Length(); ++i) { EngineID entry = (*this->engines_left)[i]; - if ( !VirtualTrainHasEngineID(entry) ) + if (!VirtualTrainHasEngineID(entry)) { this->engines_left->Erase(&((*this->engines_left)[i])); + } } } void ReplaceAll() { - - if ( this->selected_left==-1 || this->selected_right==-1 ) - return; + if (this->selected_left == -1 || this->selected_right == -1) return; EngineID eid_orig = (*this->engines_left)[this->selected_left]; EngineID eid_repl = (*this->engines_right)[this->selected_right]; - if ( eid_orig == eid_repl ) - return; + if (eid_orig == eid_repl) return; - if ( this->virtualTrains->Length() == 0 ) + if (this->virtualTrains->Length() == 0) { this->GenerateVirtualTrains(); + } - for ( uint i=0; ivirtualTrains->Length(); ++i ) { + for (uint i = 0; i < this->virtualTrains->Length(); ++i) { Train *tmp = (*this->virtualTrains)[i]->vt; - while ( tmp ) { - if ( tmp->engine_type == eid_orig ) { + while (tmp) { + if (tmp->engine_type == eid_orig) { // build a new virtual rail vehicle and test for success Train *nt = CmdBuildVirtualRailVehicle(eid_repl); - if ( !nt ) continue; + if (!nt) continue; // include the (probably) new engine into the 'included'-list - this->engines_left->Include( nt->engine_type ); + this->engines_left->Include(nt->engine_type); // advance the tmp pointer in the chain, otherwise it would get deleted later on Train *to_del = tmp; tmp = tmp->GetNextUnit(); // first move the new virtual rail vehicle behind to_del - CommandCost move = CmdMoveRailVehicle(INVALID_TILE, DC_EXEC, nt->index|(1<<21), to_del->index, 0); + CommandCost move = CmdMoveRailVehicle(INVALID_TILE, DC_EXEC, nt->index | (1 << 21), to_del->index, 0); // then move to_del away from the chain and delete it - move = CmdMoveRailVehicle(INVALID_TILE, DC_EXEC, to_del->index|(1<<21), INVALID_VEHICLE, 0); + move = CmdMoveRailVehicle(INVALID_TILE, DC_EXEC, to_del->index | (1 << 21), INVALID_VEHICLE, 0); (*this->virtualTrains)[i]->vt = nt->First(); delete to_del; } else { @@ -458,7 +495,7 @@ public: this->vscroll_tr->SetCount(this->engines_right->Length()); } - void DrawEngineList(const Rect &r, bool left) const//, GUIEngineList el, Scrollbar* sb) const + void DrawEngineList(const Rect &r, bool left) const { uint16 y = r.top; uint32 eid; @@ -466,7 +503,7 @@ public: Scrollbar *sb; const GUIEngineList *el; - if ( left ) { + if (left) { sb = this->vscroll_tl; el = this->engines_left; } else { @@ -474,22 +511,22 @@ public: el = this->engines_right; } - int maximum = min((int)sb->GetCapacity(), (int)el->Length()) + sb->GetPosition(); - - for ( int i=sb->GetPosition(); iGetCapacity(), (int) el->Length()) + sb->GetPosition(); + for (int i = sb->GetPosition(); i < maximum; ++i) { eid = (*el)[i]; /* Draw a grey background rectangle if the current line is the selected one */ - if ( (left && this->selected_left == i) || (!left && this->selected_right == i) ) - GfxFillRect(r.left, y, r.right, y+this->line_height, _colour_gradient[COLOUR_GREY][3]); + if ((left && this->selected_left == i) || (!left && this->selected_right == i)) { + GfxFillRect(r.left, y, r.right, y + this->line_height, _colour_gradient[COLOUR_GREY][3]); + } /* Draw a description string of the current engine */ SetDParam(0, eid); - DrawString(r.left+100, r.right, y+4, STR_ENGINE_NAME, TC_BLACK); + DrawString(r.left + 100, r.right, y + 4, STR_ENGINE_NAME, TC_BLACK); /* Draw the engine */ - DrawVehicleEngine( r.left, r.right, r.left+29, y+8, eid, GetEnginePalette(eid, _local_company), EIT_PURCHASE ); + DrawVehicleEngine(r.left, r.right, r.left + 29, y + 8, eid, GetEnginePalette(eid, _local_company), EIT_PURCHASE); y += this->line_height; } @@ -501,11 +538,11 @@ public: uint16 max = min(virtualTrains->Length(), this->vscroll_bo->GetCapacity()); - for ( uint16 i=vscroll_bo->GetPosition(); iGetPosition(); ++i ) { + for (uint16 i = vscroll_bo->GetPosition(); i < max + vscroll_bo->GetPosition(); ++i) { /* Draw a virtual train*/ - DrawTrainImage( (*this->virtualTrains)[i]->vt, r.left+32, r.right, y, INVALID_VEHICLE, EIT_PURCHASE, 0, -1 ); + DrawTrainImage((*this->virtualTrains)[i]->vt, r.left + 32, r.right, y, INVALID_VEHICLE, EIT_PURCHASE, 0, -1); - y+= this->line_height; + y += this->line_height; } } }; diff --git a/src/tbtr_template_gui_replaceall.h b/src/tbtr_template_gui_replaceall.h index 10b9ccd3bc..02d8aae2ca 100644 --- a/src/tbtr_template_gui_replaceall.h +++ b/src/tbtr_template_gui_replaceall.h @@ -1,27 +1,17 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file tbtr_template_gui_replaceall.cpp Template-based train replacement: replace all GUI header. */ + #ifndef TMPL_RPLALL_GUI #define TMPL_RPLALL_GUI - - -#include "stdafx.h" -#include "window_gui.h" -#include "window_func.h" - -#include "company_func.h" -#include "engine_base.h" -#include "engine_func.h" -#include "engine_gui.h" -#include "train.h" -#include "strings_func.h" -#include "vehicle_base.h" -#include "vehicle_func.h" - -#include "tbtr_template_vehicle.h" -#include "tbtr_template_vehicle_func.h" - -#include "core/math_func.hpp" -#include "table/strings.h" - void ShowTemplateReplaceAllGui(); -#endif \ No newline at end of file +#endif diff --git a/src/tbtr_template_vehicle.cpp b/src/tbtr_template_vehicle.cpp index 23036e64ba..1a87266f0d 100644 --- a/src/tbtr_template_vehicle.cpp +++ b/src/tbtr_template_vehicle.cpp @@ -1,3 +1,14 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file tbtr_template_vehicle.cpp Template-based train replacement: template vehicle. */ + #include "stdafx.h" #include "company_func.h" #include "train.h" @@ -24,7 +35,6 @@ #include "table/train_cmd.h" - #include "tbtr_template_vehicle.h" // since doing stuff with sprites @@ -32,6 +42,8 @@ #include "newgrf_engine.h" #include "newgrf_cargo.h" +#include "safeguards.h" + TemplatePool _template_pool("TemplatePool"); INSTANTIATE_POOL_METHODS(Template) @@ -74,24 +86,28 @@ void TemplateVehicle::SetFirst(TemplateVehicle *v) { this->first = v; } TemplateVehicle* TemplateVehicle::GetNextUnit() const { TemplateVehicle *tv = this->Next(); - while ( tv && HasBit(tv->subtype, GVSF_ARTICULATED_PART) ) tv = tv->Next(); - if ( tv && HasBit(tv->subtype, GVSF_MULTIHEADED) && !HasBit(tv->subtype, GVSF_ENGINE) ) tv = tv->Next(); + while (tv && HasBit(tv->subtype, GVSF_ARTICULATED_PART)) { + tv = tv->Next(); + } + if (tv && HasBit(tv->subtype, GVSF_MULTIHEADED) && !HasBit(tv->subtype, GVSF_ENGINE)) tv = tv->Next(); return tv; } TemplateVehicle* TemplateVehicle::GetPrevUnit() { TemplateVehicle *tv = this->Prev(); - while ( tv && HasBit(tv->subtype, GVSF_ARTICULATED_PART|GVSF_ENGINE) ) tv = tv->Prev(); - if ( tv && HasBit(tv->subtype, GVSF_MULTIHEADED|GVSF_ENGINE) ) tv = tv->Prev(); + while (tv && HasBit(tv->subtype, GVSF_ARTICULATED_PART|GVSF_ENGINE)) { + tv = tv->Prev(); + } + if (tv && HasBit(tv->subtype, GVSF_MULTIHEADED|GVSF_ENGINE)) tv = tv->Prev(); return tv; } /** setting */ void appendTemplateVehicle(TemplateVehicle *orig, TemplateVehicle *newv) { - if ( !orig ) return; - while ( orig->Next() ) orig=orig->Next(); + if (!orig) return; + while (orig->Next()) orig = orig->Next(); orig->SetNext(newv); newv->SetPrev(orig); newv->SetFirst(orig->First()); @@ -99,7 +115,7 @@ void appendTemplateVehicle(TemplateVehicle *orig, TemplateVehicle *newv) void insertTemplateVehicle(TemplateVehicle *orig, TemplateVehicle *newv, TemplateVehicle *insert_after) { - if ( !orig || !insert_after ) return; + if (!orig || !insert_after) return; TemplateVehicle *insert_before = insert_after->Next(); insert_after->SetNext(newv); insert_before->SetPrev(newv); @@ -113,9 +129,12 @@ void insertTemplateVehicle(TemplateVehicle *orig, TemplateVehicle *newv, Templat */ int TemplateVehicle::Length() const { - int l=1; - const TemplateVehicle *tmp=this; - while ( tmp->Next() ) { tmp=tmp->Next(); l++; } + int l = 1; + const TemplateVehicle *tmp = this; + while (tmp->Next()) { + tmp = tmp->Next(); + l++; + } return l; } @@ -123,32 +142,33 @@ TemplateReplacement* GetTemplateReplacementByGroupID(GroupID gid) { TemplateReplacement *tr; FOR_ALL_TEMPLATE_REPLACEMENTS(tr) { - if ( tr->Group() == gid ) + if (tr->Group() == gid) { return tr; + } } - return 0; + return NULL; } -TemplateReplacement* GetTemplateReplacementByTemplateID(TemplateID tid) { +TemplateReplacement* GetTemplateReplacementByTemplateID(TemplateID tid) +{ TemplateReplacement *tr; FOR_ALL_TEMPLATE_REPLACEMENTS(tr) { - if ( tr->Template() == tid ) + if (tr->Template() == tid) { return tr; + } } - return 0; + return NULL; } -bool IssueTemplateReplacement(GroupID gid, TemplateID tid) { - +bool IssueTemplateReplacement(GroupID gid, TemplateID tid) +{ TemplateReplacement *tr = GetTemplateReplacementByGroupID(gid); - if ( tr ) { + if (tr) { /* Then set the new TemplateVehicle and return */ tr->SetTemplate(tid); return true; - } - - else if ( TemplateReplacement::CanAllocateItem() ) { + } else if (TemplateReplacement::CanAllocateItem()) { tr = new TemplateReplacement(gid, tid); return true; } @@ -161,8 +181,9 @@ short TemplateVehicle::NumGroupsUsingTemplate() const short amount = 0; const TemplateReplacement *tr; FOR_ALL_TEMPLATE_REPLACEMENTS(tr) { - if ( tr->sel_template == this->index ) + if (tr->sel_template == this->index) { amount++; + } } return amount; } @@ -171,9 +192,11 @@ short TemplateVehicle::CountEnginesInChain() { TemplateVehicle *tv = this->first; short count = 0; - for ( ; tv; tv=tv->GetNextUnit() ) - if ( HasBit(tv->subtype, GVSF_ENGINE ) ) + for (; tv != NULL; tv = tv->GetNextUnit()) { + if (HasBit(tv->subtype, GVSF_ENGINE)) { count++; + } + } return count; } @@ -182,46 +205,10 @@ short deleteIllegalTemplateReplacements(GroupID g_id) short del_amount = 0; const TemplateReplacement *tr; FOR_ALL_TEMPLATE_REPLACEMENTS(tr) { - if ( tr->group == g_id ) { + if (tr->group == g_id) { delete tr; del_amount++; } } return del_amount; } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/tbtr_template_vehicle.h b/src/tbtr_template_vehicle.h index 1773cddc2d..0631f85b8d 100644 --- a/src/tbtr_template_vehicle.h +++ b/src/tbtr_template_vehicle.h @@ -1,3 +1,14 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file tbtr_template_vehicle.h Template-based train replacement: template vehicle header. */ + #ifndef TEMPLATE_VEH_H #define TEMPLATE_VEH_H @@ -56,7 +67,7 @@ public: bool refit_as_template; // Things derived from a virtual train - TemplateVehicle *other_multiheaded_part; ///< Multiheaded Engine support + TemplateVehicle *other_multiheaded_part; ///< Multiheaded Engine support Money value; ///< Value of the vehicle Owner owner; OwnerByte owner_b; @@ -83,17 +94,20 @@ public: uint32 image_width; const SpriteGroup *sgroup; - TemplateVehicle(VehicleType type=VEH_INVALID, EngineID e=INVALID_ENGINE, byte B=0, Owner=_local_company); + TemplateVehicle(VehicleType type = VEH_INVALID, EngineID e = INVALID_ENGINE, byte B = 0, Owner = _local_company); TemplateVehicle(EngineID, RailVehicleInfo*); - TemplateVehicle(EngineID eid) { - next=0; - previous=0; - first=this; - engine_type=eid; + + TemplateVehicle(EngineID eid) + { + next = NULL; + previous = NULL; + first = this; + engine_type = eid; this->reuse_depot_vehicles = true; this->keep_remaining_vehicles = true; this->refit_as_template = true; } + ~TemplateVehicle(); inline TemplateVehicle* Next() const { return this->next; } @@ -124,10 +138,10 @@ public: inline bool IsFreeWagonChain() const { return HasBit(this->subtype, GVSF_FREE_WAGON); } // since CmdBuildTemplateVehicle(...) - inline void SetFrontEngine() { SetBit(this->subtype, GVSF_FRONT); } - inline void SetEngine() { SetBit(this->subtype, GVSF_ENGINE); } - inline void SetArticulatedPart() { SetBit(this->subtype, GVSF_ARTICULATED_PART); } - inline void SetMultiheaded() { SetBit(this->subtype, GVSF_MULTIHEADED); } + inline void SetFrontEngine() { SetBit(this->subtype, GVSF_FRONT); } + inline void SetEngine() { SetBit(this->subtype, GVSF_ENGINE); } + inline void SetArticulatedPart() { SetBit(this->subtype, GVSF_ARTICULATED_PART); } + inline void SetMultiheaded() { SetBit(this->subtype, GVSF_MULTIHEADED); } inline void SetWagon() { SetBit(this->subtype, GVSF_WAGON); } inline void SetFreeWagon() { SetBit(this->subtype, GVSF_FREE_WAGON); } @@ -138,7 +152,6 @@ public: int Length() const; SpriteID GetImage(Direction) const; - //int GetDisplayImageWidth(Point *offset = NULL) const; SpriteID GetSpriteID() const; short NumGroupsUsingTemplate() const; @@ -173,11 +186,14 @@ struct TemplateReplacement : TemplateReplacementPool::PoolItem<&_template_replac inline void SetTemplate(TemplateID tid) { this->sel_template = tid; } inline TemplateID GetTemplateVehicleID() { return sel_template; } - inline const TemplateVehicle* GetTemplateVehicle() { + + inline const TemplateVehicle* GetTemplateVehicle() + { const TemplateVehicle *tv; FOR_ALL_TEMPLATES(tv) { - if ( tv->index == this->sel_template ) + if (tv->index == this->sel_template) { return tv; + } } return NULL; } @@ -190,4 +206,3 @@ bool IssueTemplateReplacement(GroupID, TemplateID); short deleteIllegalTemplateReplacements(GroupID); #endif /* TEMPLATE_VEH_H */ - diff --git a/src/tbtr_template_vehicle_func.cpp b/src/tbtr_template_vehicle_func.cpp index 55cfdc01c0..087d48ea57 100644 --- a/src/tbtr_template_vehicle_func.cpp +++ b/src/tbtr_template_vehicle_func.cpp @@ -1,4 +1,13 @@ -// template_vehicle_func.cpp +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file tbtr_template_vehicle_func.cpp Template-based train replacement: template vehicle functions. */ #include "stdafx.h" #include "window_gui.h" @@ -31,6 +40,8 @@ #include #include +#include "safeguards.h" + Vehicle *vhead, *vtmp; static const uint MAX_ARTICULATED_PARTS = 100; @@ -77,9 +88,9 @@ void BuildTemplateGuiList(GUITemplateList *list, Scrollbar *vscroll, Owner oid, const TemplateVehicle *tv; FOR_ALL_TEMPLATES(tv) { - if (tv->owner == oid && (tv->IsPrimaryVehicle() || tv->IsFreeWagonChain()) && TemplateVehicleContainsEngineOfRailtype(tv, railtype)) + if (tv->owner == oid && (tv->IsPrimaryVehicle() || tv->IsFreeWagonChain()) && TemplateVehicleContainsEngineOfRailtype(tv, railtype)) { *list->Append() = tv; - + } } list->RebuildDone(); @@ -90,21 +101,22 @@ Money CalculateOverallTemplateCost(const TemplateVehicle *tv) { Money val = 0; - for (; tv; tv = tv->Next()) + for (; tv; tv = tv->Next()) { val += (Engine::Get(tv->engine_type))->GetCost(); + } return val; } void DrawTemplate(const TemplateVehicle *tv, int left, int right, int y) { - if ( !tv ) return; + if (!tv) return; const TemplateVehicle *t = tv; - int offset=left; + int offset = left; while (t) { PaletteID pal = GetEnginePalette(t->engine_type, _current_company); - DrawSprite(t->cur_image, pal, offset, y+12); + DrawSprite(t->cur_image, pal, offset, y + 12); offset += t->image_width; t = t->Next(); @@ -145,17 +157,18 @@ inline void SetupTemplateVehicleFromVirtual(TemplateVehicle *tmp, TemplateVehicl // create a full TemplateVehicle based train according to a virtual train TemplateVehicle* TemplateVehicleFromVirtualTrain(Train *virt) { - if ( !virt ) - return 0; + if (!virt) return NULL; Train *init_virt = virt; int len = CountVehiclesInChain(virt); - if ( !TemplateVehicle::CanAllocateItem(len) ) - return 0; + if (!TemplateVehicle::CanAllocateItem(len)) { + return NULL; + } - TemplateVehicle *tmp, *prev=0; - for ( ; virt; virt=virt->Next() ) { + TemplateVehicle *tmp; + TemplateVehicle *prev = NULL; + for (; virt; virt = virt->Next()) { tmp = new TemplateVehicle(virt->engine_type); SetupTemplateVehicleFromVirtual(tmp, prev, virt); prev = tmp; @@ -166,23 +179,28 @@ TemplateVehicle* TemplateVehicleFromVirtualTrain(Train *virt) } // return last in a chain (really last, so even a singular articulated part of a vehicle if the last one is artic) -inline TemplateVehicle* Last(TemplateVehicle *chain) { - if ( !chain ) return 0; - while ( chain->Next() ) chain = chain->Next(); +inline TemplateVehicle* Last(TemplateVehicle *chain) +{ + if (!chain) return NULL; + while (chain->Next()) { + chain = chain->Next(); + } return chain; } -inline Train* Last(Train *chain) { - if ( !chain ) return 0; - while ( chain->GetNextUnit() ) chain = chain->GetNextUnit(); +inline Train* Last(Train *chain) +{ + if (!chain) return NULL; + while (chain->GetNextUnit()) { + chain = chain->GetNextUnit(); + } return chain; } // return: pointer to former vehicle TemplateVehicle *DeleteTemplateVehicle(TemplateVehicle *todel) { - if ( !todel ) - return 0; + if (!todel) return NULL; TemplateVehicle *cur = todel; delete todel; return cur; @@ -192,7 +210,7 @@ TemplateVehicle *DeleteTemplateVehicle(TemplateVehicle *todel) CommandCost CmdSellRailWagon(DoCommandFlag, Vehicle*, uint16, uint32); Train* DeleteVirtualTrain(Train *chain, Train *to_del) { - if ( chain != to_del ) { + if (chain != to_del) { CmdSellRailWagon(DC_EXEC, to_del, 0, 0); return chain; } @@ -208,17 +226,20 @@ TemplateVehicle* GetTemplateVehicleByGroupID(GroupID gid) { TemplateReplacement *tr; // first try to find a templatereplacement issued for the given groupid FOR_ALL_TEMPLATE_REPLACEMENTS(tr) { - if ( tr->Group() == gid ) - return TemplateVehicle::GetIfValid(tr->Template()); // there can be only one + if (tr->Group() == gid) { + return TemplateVehicle::GetIfValid(tr->Template()); // there can be only one + } } // if that didn't work, try to find a templatereplacement for ALL_GROUP - if ( gid != ALL_GROUP ) + if (gid != ALL_GROUP) { FOR_ALL_TEMPLATE_REPLACEMENTS(tr) { - if ( tr->Group() == ALL_GROUP ) + if (tr->Group() == ALL_GROUP) { return TemplateVehicle::GetIfValid(tr->Template()); + } } + } // if all failed, just return null - return 0; + return NULL; } /** @@ -227,28 +248,33 @@ TemplateVehicle* GetTemplateVehicleByGroupID(GroupID gid) { bool TemplateVehicleContainsEngineOfRailtype(const TemplateVehicle *tv, RailType type) { /* For standard rail engines, allow only those */ - if ( type == RAILTYPE_BEGIN || type == RAILTYPE_RAIL ) { - while ( tv ) { - if ( tv->railtype != type ) - return false; - tv = tv->GetNextUnit(); + if (type == RAILTYPE_BEGIN || type == RAILTYPE_RAIL) { + while (tv) { + if (tv->railtype != type) { + return false; + } + tv = tv->GetNextUnit(); } return true; } /* For electrified rail engines, standard wagons or engines are allowed to be included */ - while ( tv ) { - if ( tv->railtype == type ) + while (tv) { + if (tv->railtype == type) { return true; + } tv = tv->GetNextUnit(); } return false; } //helper -bool ChainContainsVehicle(Train *chain, Train *mem) { - for (; chain; chain=chain->Next()) - if ( chain == mem ) +bool ChainContainsVehicle(Train *chain, Train *mem) +{ + for (; chain; chain = chain->Next()) { + if (chain == mem) { return true; + } + } return false; } @@ -257,27 +283,30 @@ Train* ChainContainsEngine(EngineID eid, Train *chain) { for (; chain; chain=chain->GetNextUnit()) if (chain->engine_type == eid) return chain; - return 0; + return NULL; } // has O(n^2) -Train* DepotContainsEngine(TileIndex tile, EngineID eid, Train *not_in=0) { +Train* DepotContainsEngine(TileIndex tile, EngineID eid, Train *not_in = NULL) +{ Train *t; FOR_ALL_TRAINS(t) { // conditions: v is stopped in the given depot, has the right engine and if 'not_in' is given v must not be contained within 'not_in' // if 'not_in' is NULL, no check is needed - if ( t->tile==tile + if (t->tile == tile // If the veh belongs to a chain, wagons will not return true on IsStoppedInDepot(), only primary vehicles will // in case of t not a primary veh, we demand it to be a free wagon to consider it for replacement && ((t->IsPrimaryVehicle() && t->IsStoppedInDepot()) || t->IsFreeWagon()) - && t->engine_type==eid - && (not_in==0 || ChainContainsVehicle(not_in, t)==0)) + && t->engine_type == eid + && (not_in == NULL || ChainContainsVehicle(not_in, t) == false)) { return t; + } } - return 0; + return NULL; } -void CopyStatus(Train *from, Train *to) { +void CopyStatus(Train *from, Train *to) +{ DoCommand(to->tile, from->group_id, to->index, DC_EXEC, CMD_ADD_VEHICLE_GROUP); to->cargo_type = from->cargo_type; to->cargo_subtype = from->cargo_subtype; @@ -286,117 +315,133 @@ void CopyStatus(Train *from, Train *to) { char *tmp = to->name; to->name = from->name; from->name = tmp; - /*if ( !from->name || !to->name ) { - int tmpind = from->index; - from->index = to->index; - to->index = tmpind; - }*/ } -void NeutralizeStatus(Train *t) { + +void NeutralizeStatus(Train *t) +{ DoCommand(t->tile, DEFAULT_GROUP, t->index, DC_EXEC, CMD_ADD_VEHICLE_GROUP); DoCommand(0, t->index | CO_UNSHARE << 30, 0, DC_EXEC, CMD_CLONE_ORDER); DoCommand(0, t->index, FreeUnitIDGenerator(VEH_TRAIN, t->owner).NextID(), DC_EXEC, CMD_SET_VEHICLE_UNIT_NUMBER); DoCommand(0, t->index, 0, DC_EXEC, CMD_RENAME_VEHICLE, NULL); } + bool TrainMatchesTemplate(const Train *t, TemplateVehicle *tv) { - while ( t && tv ) { - if ( t->engine_type != tv->engine_type ) + while (t && tv) { + if (t->engine_type != tv->engine_type) { return false; + } t = t->GetNextUnit(); tv = tv->GetNextUnit(); } - if ( (t && !tv) || (!t && tv) ) + if ((t && !tv) || (!t && tv)) { return false; + } return true; } bool TrainMatchesTemplateRefit(const Train *t, TemplateVehicle *tv) { - if ( !tv->refit_as_template ) + if (!tv->refit_as_template) { return true; + } - while ( t && tv ) { - if ( t->cargo_type != tv->cargo_type || t->cargo_subtype != tv->cargo_subtype ) + while (t && tv) { + if (t->cargo_type != tv->cargo_type || t->cargo_subtype != tv->cargo_subtype) { return false; + } t = t->GetNextUnit(); tv = tv->GetNextUnit(); } return true; } -void BreakUpRemainders(Train *t) { - while ( t ) { + +void BreakUpRemainders(Train *t) +{ + while (t) { Train *move; - if ( HasBit(t->subtype, GVSF_ENGINE) ) { + if (HasBit(t->subtype, GVSF_ENGINE)) { move = t; t = t->Next(); DoCommand(move->tile, move->index, INVALID_VEHICLE, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); - NeutralizeStatus( move ); - } - else + NeutralizeStatus(move); + } else { t = t->Next(); + } } } short CountEnginesInChain(Train *t) { short count = 0; - for ( ; t; t=t->GetNextUnit() ) - if ( HasBit(t->subtype, GVSF_ENGINE) ) + for (; t != NULL; t = t->GetNextUnit()) { + if (HasBit(t->subtype, GVSF_ENGINE)) { count++; + } + } return count; } -int countOccurrencesInTrain(Train *t, EngineID eid) { +int countOccurrencesInTrain(Train *t, EngineID eid) +{ int count = 0; Train *tmp = t; - for ( ; tmp; tmp=tmp->GetNextUnit() ) - if ( tmp->engine_type == eid ) + for (; tmp != NULL; tmp = tmp->GetNextUnit()) { + if (tmp->engine_type == eid) { count++; + } + } return count; } -int countOccurrencesInTemplateVehicle(TemplateVehicle *contain, EngineID eid) { +int countOccurrencesInTemplateVehicle(TemplateVehicle *contain, EngineID eid) +{ int count = 0; - for ( ; contain; contain=contain->GetNextUnit() ) - if ( contain->engine_type == eid ) + for (; contain; contain=contain->GetNextUnit()) { + if (contain->engine_type == eid) { count++; + } + } return count; } -int countOccurrencesInDepot(TileIndex tile, EngineID eid, Train *not_in=0) { +int countOccurrencesInDepot(TileIndex tile, EngineID eid, Train *not_in = NULL) +{ int count = 0; Vehicle *v; FOR_ALL_VEHICLES(v) { // conditions: v is stopped in the given depot, has the right engine and if 'not_in' is given v must not be contained within 'not_in' // if 'not_in' is NULL, no check is needed - if ( v->tile==tile && v->IsStoppedInDepot() && v->engine_type==eid && - (not_in==0 || ChainContainsVehicle(not_in, (Train*)v)==0)) + if (v->tile == tile && v->IsStoppedInDepot() && v->engine_type == eid && + (not_in == 0 || ChainContainsVehicle(not_in, (Train*)v) == false)) { count++; + } } return count; } // basically does the same steps as CmdTemplateReplaceVehicle but without actually moving things around -CommandCost CalculateTemplateReplacementCost(Train *incoming) { +CommandCost CalculateTemplateReplacementCost(Train *incoming) +{ TileIndex tile = incoming->tile; TemplateVehicle *tv = GetTemplateVehicleByGroupID(incoming->group_id); CommandCost estimate(EXPENSES_NEW_VEHICLES); // count for each different eid in the incoming train std::map unique_eids; - for ( TemplateVehicle *tmp=tv; tmp; tmp=tmp->GetNextUnit() ) + for (TemplateVehicle *tmp = tv; tmp != NULL; tmp = tmp->GetNextUnit()) { unique_eids[tmp->engine_type]++; + } std::map::iterator it = unique_eids.begin(); - for ( ; it!=unique_eids.end(); it++ ) { + for (; it != unique_eids.end(); it++) { it->second -= countOccurrencesInTrain(incoming, it->first); it->second -= countOccurrencesInDepot(incoming->tile, it->first, incoming); - if ( it->second < 0 ) it->second = 0; + if (it->second < 0) it->second = 0; } // get overall buying cost - for ( it=unique_eids.begin(); it!=unique_eids.end(); it++ ) { - for ( int j=0; jsecond; j++ ) { + for (it = unique_eids.begin(); it != unique_eids.end(); it++) { + for (int j = 0; j < it->second; j++) { estimate.AddCost(DoCommand(tile, it->first, 0, DC_NONE, CMD_BUILD_VEHICLE)); } } @@ -405,7 +450,8 @@ CommandCost CalculateTemplateReplacementCost(Train *incoming) { } // make sure the real train wagon has the right cargo -void CopyWagonStatus(TemplateVehicle *from, Train *to) { +void CopyWagonStatus(TemplateVehicle *from, Train *to) +{ to->cargo_type = from->cargo_type; to->cargo_subtype = from->cargo_subtype; } @@ -413,19 +459,20 @@ void CopyWagonStatus(TemplateVehicle *from, Train *to) { int NumTrainsNeedTemplateReplacement(GroupID g_id, TemplateVehicle *tv) { int count = 0; - if ( !tv ) return count; + if (!tv) return count; const Train *t; FOR_ALL_TRAINS(t) { - if ( t->IsPrimaryVehicle() && t->group_id == g_id && (!TrainMatchesTemplate(t, tv) || !TrainMatchesTemplateRefit(t, tv)) ) + if (t->IsPrimaryVehicle() && t->group_id == g_id && (!TrainMatchesTemplate(t, tv) || !TrainMatchesTemplateRefit(t, tv))) { count++; + } } return count; } // refit each vehicle in t as is in tv, assume t and tv contain the same types of vehicles void CmdRefitTrainFromTemplate(Train *t, TemplateVehicle *tv, DoCommandFlag flags) { - while ( t && tv ) { + while (t && tv) { // refit t as tv uint32 cb = GetCmdRefitVeh(t); @@ -445,8 +492,9 @@ CommandCost TestBuyAllTemplateVehiclesInChain(TemplateVehicle *tv, TileIndex til { CommandCost cost(EXPENSES_NEW_VEHICLES); - for ( ; tv; tv=tv->GetNextUnit() ) - cost.AddCost( DoCommand(tile, tv->engine_type, 0, DC_NONE, CMD_BUILD_VEHICLE) ); + for (; tv; tv = tv->GetNextUnit()) { + cost.AddCost(DoCommand(tile, tv->engine_type, 0, DC_NONE, CMD_BUILD_VEHICLE)); + } return cost; } @@ -455,9 +503,9 @@ CommandCost TestBuyAllTemplateVehiclesInChain(TemplateVehicle *tv, TileIndex til /** Transfer as much cargo from a given (single train) vehicle onto a chain of vehicles. * I.e., iterate over the chain from head to tail and use all available cargo capacity (w.r.t. cargo type of course) * to store the cargo from the given single vehicle. - * @param old_veh: ptr to the single vehicle, which's cargo shall be moved - * @param new_head: ptr to the head of the chain, which shall obtain old_veh's cargo - * @return: amount of moved cargo TODO + * @param old_veh: ptr to the single vehicle, which's cargo shall be moved + * @param new_head: ptr to the head of the chain, which shall obtain old_veh's cargo + * @return: amount of moved cargo, TODO */ void TransferCargoForTrain(Train *old_veh, Train *new_head) { @@ -469,16 +517,13 @@ void TransferCargoForTrain(Train *old_veh, Train *new_head) // how much cargo has to be moved (if possible) uint remainingAmount = old_veh->cargo.TotalCount(); // each vehicle in the new chain shall be given as much of the old cargo as possible, until none is left - for (Train *tmp=new_head; tmp!=NULL && remainingAmount>0; tmp=tmp->GetNextUnit()) - { - if (tmp->cargo_type == _cargo_type && tmp->cargo_subtype == _cargo_subtype) - { + for (Train *tmp = new_head; tmp != NULL && remainingAmount > 0; tmp = tmp->GetNextUnit()) { + if (tmp->cargo_type == _cargo_type && tmp->cargo_subtype == _cargo_subtype) { // calculate the free space for new cargo on the current vehicle uint curCap = tmp->cargo_cap - tmp->cargo.TotalCount(); uint moveAmount = min(remainingAmount, curCap); // move (parts of) the old vehicle's cargo onto the current vehicle of the new chain - if (moveAmount > 0) - { + if (moveAmount > 0) { old_veh->cargo.Shift(moveAmount, &tmp->cargo); remainingAmount -= moveAmount; } @@ -493,33 +538,3 @@ void TransferCargoForTrain(Train *old_veh, Train *new_head) /* Update train weight etc., the old vehicle will be sold anyway */ new_head->ConsistChanged(CCF_LOADUNLOAD); } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/tbtr_template_vehicle_func.h b/src/tbtr_template_vehicle_func.h index 2078191090..b2900374b4 100644 --- a/src/tbtr_template_vehicle_func.h +++ b/src/tbtr_template_vehicle_func.h @@ -1,4 +1,14 @@ -// template_vehicle_func.h +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file tbtr_template_vehicle_func.h Template-based train replacement: template vehicle functions headers. */ + #ifndef TEMPLATE_VEHICLE_FUNC_H #define TEMPLATE_VEHICLE_FUNC_H @@ -7,9 +17,6 @@ #include "tbtr_template_vehicle.h" -//void DrawTemplateVehicle(TemplateVehicle*, int, const Rect&); - - Train* VirtualTrainFromTemplateVehicle(TemplateVehicle* tv); void DrawTemplateVehicle(const TemplateVehicle*, int, int, int, VehicleID, int, VehicleID); @@ -32,8 +39,6 @@ void setupVirtTrain(const TemplateVehicle*, Train*); TemplateVehicle* TemplateVehicleFromVirtualTrain(Train *virt); -//Train* VirtualTrainFromTemplateVehicle(TemplateVehicle*); - inline TemplateVehicle* Last(TemplateVehicle*); TemplateVehicle *DeleteTemplateVehicle(TemplateVehicle*); diff --git a/src/train.h b/src/train.h index 70bda2a7cb..99b6699dc2 100644 --- a/src/train.h +++ b/src/train.h @@ -169,7 +169,9 @@ struct Train FINAL : public GroundVehicle { */ inline Train *GetLastUnit() { Train *tmp = this; - while ( tmp->GetNextUnit() ) tmp = tmp->GetNextUnit(); + while (tmp->GetNextUnit()) { + tmp = tmp->GetNextUnit(); + } return tmp; } diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 511669a40e..091b638c24 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -262,7 +262,7 @@ void Train::ConsistChanged(ConsistChangeFlags allowed_changes) if (this->IsFrontEngine()) { this->UpdateAcceleration(); - if ( !HasBit(this->subtype, GVSF_VIRTUAL) ) SetWindowDirty(WC_VEHICLE_DETAILS, this->index); + if (!HasBit(this->subtype, GVSF_VIRTUAL)) SetWindowDirty(WC_VEHICLE_DETAILS, this->index); InvalidateWindowData(WC_VEHICLE_REFIT, this->index, VIWD_CONSIST_CHANGED); InvalidateWindowData(WC_VEHICLE_ORDERS, this->index, VIWD_CONSIST_CHANGED); InvalidateNewGRFInspectWindow(GSF_TRAINS, this->index); @@ -1161,7 +1161,7 @@ static void NormaliseTrainHead(Train *head) * @param p1 various bitstuffed elements * - p1 (bit 0 - 19) source vehicle index * - p1 (bit 20) move all vehicles following the source vehicle - * - p1 (bit 21) this is a virtual vehicle (for creating TemplateVehicles) + * - p1 (bit 21) this is a virtual vehicle (for creating TemplateVehicles) * @param p2 what wagon to put the source wagon AFTER, XXX - INVALID_VEHICLE to make a new line * @param text unused * @return the cost of this operation or an error @@ -1227,13 +1227,15 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u /* Check if all vehicles in the source train are stopped inside a depot. */ /* Do this check only if the vehicle to be moved is non-virtual */ - if ( !HasBit(p1, 21) ) + if (!HasBit(p1, 21)) { if (!src_head->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT); + } /* Check if all vehicles in the destination train are stopped inside a depot. */ /* Do this check only if the destination vehicle is non-virtual */ - if ( !HasBit(p1, 21) ) + if (!HasBit(p1, 21)) { if (dst_head != NULL && !dst_head->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT); + } /* First make a backup of the order of the trains. That way we can do * whatever we want with the order and later on easily revert. */ @@ -1343,7 +1345,7 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u /* We are undoubtedly changing something in the depot and train list. */ /* But only if the moved vehicle is not virtual */ - if ( !HasBit(src->subtype, GVSF_VIRTUAL) ) { + if (!HasBit(src->subtype, GVSF_VIRTUAL)) { InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile); InvalidateWindowClassesData(WC_TRAINS_LIST, 0); } @@ -1430,7 +1432,7 @@ CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data, uint3 /* We are undoubtedly changing something in the depot and train list. */ /* Unless its a virtual train */ - if ( !HasBit(v->subtype, GVSF_VIRTUAL) ) { + if (!HasBit(v->subtype, GVSF_VIRTUAL)) { InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); InvalidateWindowClassesData(WC_TRAINS_LIST, 0); } @@ -3762,7 +3764,7 @@ Money Train::CalculateCurrentOverallValue() const const Train *v = this; do { ovr_value += v->value; - } while ( (v=v->GetNextVehicle()) != NULL ); + } while ((v = v->GetNextVehicle()) != NULL); return ovr_value; } @@ -4060,7 +4062,6 @@ Trackdir Train::GetVehicleTrackdir() const return TrackDirectionToTrackdir(FindFirstTrack(this->track), this->direction); } - /* Get the pixel-width of the image that is used for the train vehicle * @return: the image width number in pixel */ @@ -4079,7 +4080,6 @@ int GetDisplayImageWidth(Train *t, Point *offset) offset->x = reference_width / 2; offset->y = vehicle_pitch; } - //printf(" refwid:%d gdiw.cachedvehlen(%d):%d ", reference_width, this->engine_type, this->gcache.cached_veh_length); return t->gcache.cached_veh_length * reference_width / VEHICLE_LENGTH; } @@ -4098,7 +4098,7 @@ Train* CmdBuildVirtualRailWagon(const Engine *e) v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback v->direction = DIR_W; - v->tile = 0;//INVALID_TILE; + v->tile = 0; // INVALID_TILE; v->owner = _current_company; v->track = TRACK_BIT_DEPOT; @@ -4147,18 +4147,21 @@ Train* CmdBuildVirtualRailWagon(const Engine *e) */ Train* CmdBuildVirtualRailVehicle(EngineID eid) { - if (!IsEngineBuildable(eid, VEH_TRAIN, _current_company)) - return nullptr; + if (!IsEngineBuildable(eid, VEH_TRAIN, _current_company)) { + return NULL; + } const Engine* e = Engine::Get(eid); const RailVehicleInfo *rvi = &e->u.rail; int num_vehicles = (e->u.rail.railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) + CountArticulatedParts(eid, false); - if (!Train::CanAllocateItem(num_vehicles)) - return nullptr; + if (!Train::CanAllocateItem(num_vehicles)) { + return NULL; + } - if (rvi->railveh_type == RAILVEH_WAGON) + if (rvi->railveh_type == RAILVEH_WAGON) { return CmdBuildVirtualRailWagon(e); + } Train *v = new Train(); @@ -4166,7 +4169,7 @@ Train* CmdBuildVirtualRailVehicle(EngineID eid) v->y_pos = 0; v->direction = DIR_W; - v->tile = 0;//INVALID_TILE; + v->tile = 0; // INVALID_TILE; v->owner = _current_company; v->track = TRACK_BIT_DEPOT; v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL; @@ -4225,15 +4228,15 @@ Train* CmdBuildVirtualRailVehicle(EngineID eid) CommandCost CmdBuildVirtualRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { EngineID eid = p1; - CommandCost cost = CommandCost(); bool should_execute = (flags & DC_EXEC) != 0; if (should_execute) { Train* train = CmdBuildVirtualRailVehicle(eid); - if (train == nullptr) + if (train == NULL) { return CMD_ERROR; + } } return CommandCost(); @@ -4254,20 +4257,22 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3 Vehicle* vehicle = Vehicle::GetIfValid(vehicle_id); - if (vehicle == nullptr || vehicle->type != VEH_TRAIN) + if (vehicle == NULL || vehicle->type != VEH_TRAIN) { return CMD_ERROR; + } bool should_execute = (flags & DC_EXEC) != 0; - if (!should_execute) + if (!should_execute) { return CommandCost(); + } Train* incoming = Train::From(vehicle); bool stayInDepot = p2 != 0; - Train *new_chain = 0, - *remainder_chain = 0, - *tmp_chain = 0; + Train *new_chain = NULL; + Train *remainder_chain = NULL; + Train *tmp_chain = NULL; TemplateVehicle *tv = GetTemplateVehicleByGroupID(incoming->group_id); EngineID eid = tv->engine_type; @@ -4277,8 +4282,7 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3 /* first some tests on necessity and sanity */ - if (!tv) - return buy; + if (tv == NULL) return buy; bool need_replacement = !TrainMatchesTemplate(incoming, tv); bool need_refit = !TrainMatchesTemplateRefit(incoming, tv); bool use_refit = tv->refit_as_template; @@ -4286,7 +4290,7 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3 short store_refit_csubt = 0; // if a train shall keep its old refit, store the refit setting of its first vehicle if (!use_refit) { - for (Train *getc = incoming; getc; getc = getc->GetNextUnit()) + for (Train *getc = incoming; getc != NULL; getc = getc->GetNextUnit()) if (getc->cargo_type != CT_INVALID) { store_refit_ct = getc->cargo_type; break; @@ -4300,8 +4304,7 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3 if (!stayInDepot) incoming->vehstatus &= ~VS_STOPPED; return buy; } - } - else { + } else { CommandCost buyCost = TestBuyAllTemplateVehiclesInChain(tv, tile); if (!buyCost.Succeeded() || !CheckCompanyHasMoney(buyCost)) { if (!stayInDepot) incoming->vehstatus &= ~VS_STOPPED; @@ -4314,35 +4317,34 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3 bool keepRemainders = tv->IsSetKeepRemainingVehicles(); if (need_replacement) { - /// step 1: generate primary for newchain and generate remainder_chain + // step 1: generate primary for newchain and generate remainder_chain // 1. primary of incoming might already fit the template - // leave incoming's primary as is and move the rest to a free chain = remainder_chain + // leave incoming's primary as is and move the rest to a free chain = remainder_chain // 2. needed primary might be one of incoming's member vehicles // 3. primary might be available as orphan vehicle in the depot // 4. we need to buy a new engine for the primary // all options other than 1. need to make sure to copy incoming's primary's status - if (eid == incoming->engine_type) { // 1 + if (eid == incoming->engine_type) { // 1 new_chain = incoming; remainder_chain = incoming->GetNextUnit(); - if (remainder_chain) + if (remainder_chain) { move_cost.AddCost(CmdMoveRailVehicle(tile, flags, remainder_chain->index | (1 << 20), INVALID_VEHICLE, 0)); - } - else if ((tmp_chain = ChainContainsEngine(eid, incoming)) && tmp_chain != NULL) { // 2 + } + } else if ((tmp_chain = ChainContainsEngine(eid, incoming)) && tmp_chain != NULL) { // 2 // new_chain is the needed engine, move it to an empty spot in the depot new_chain = tmp_chain; move_cost.AddCost(DoCommand(tile, new_chain->index, INVALID_VEHICLE, flags, CMD_MOVE_RAIL_VEHICLE)); remainder_chain = incoming; - } - else if (reuseDepot && (tmp_chain = DepotContainsEngine(tile, eid, incoming)) && tmp_chain != NULL) { // 3 + } else if (reuseDepot && (tmp_chain = DepotContainsEngine(tile, eid, incoming)) && tmp_chain != NULL) { // 3 new_chain = tmp_chain; move_cost.AddCost(DoCommand(tile, new_chain->index, INVALID_VEHICLE, flags, CMD_MOVE_RAIL_VEHICLE)); remainder_chain = incoming; - } - else { // 4 + } else { // 4 tmp_result = DoCommand(tile, eid, 0, flags, CMD_BUILD_VEHICLE); /* break up in case buying the vehicle didn't succeed */ - if (!tmp_result.Succeeded()) + if (!tmp_result.Succeeded()) { return tmp_result; + } buy.AddCost(tmp_result); new_chain = Train::Get(_new_vehicle_id); /* make sure the newly built engine is not attached to any free wagons inside the depot */ @@ -4355,29 +4357,28 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3 CopyHeadSpecificThings(incoming, new_chain, flags); NeutralizeStatus(incoming); - // additionally, if we don't want to use the template refit, refit as incoming // the template refit will be set further down, if we use it at all if (!use_refit) { uint32 cb = GetCmdRefitVeh(new_chain); DoCommand(new_chain->tile, new_chain->index, store_refit_ct | store_refit_csubt << 8 | 1 << 16 | (1 << 5), flags, cb); } - } - /// step 2: fill up newchain according to the template + // step 2: fill up newchain according to the template // foreach member of template (after primary): // 1. needed engine might be within remainder_chain already // 2. needed engine might be orphaned within the depot (copy status) - // 3. we need to buy (again) (copy status) + // 3. we need to buy (again) (copy status) TemplateVehicle *cur_tmpl = tv->GetNextUnit(); Train *last_veh = new_chain; while (cur_tmpl) { // 1. engine contained in remainder chain if ((tmp_chain = ChainContainsEngine(cur_tmpl->engine_type, remainder_chain)) && tmp_chain != NULL) { // advance remainder_chain (if necessary) to not lose track of it - if (tmp_chain == remainder_chain) + if (tmp_chain == remainder_chain) { remainder_chain = remainder_chain->GetNextUnit(); + } move_cost.AddCost(CmdMoveRailVehicle(tile, flags, tmp_chain->index, last_veh->index, 0)); } // 2. engine contained somewhere else in the depot @@ -4397,13 +4398,11 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3 if (need_refit && flags == DC_EXEC) { if (use_refit) { uint32 cb = GetCmdRefitVeh(tmp_chain); - DoCommand(tmp_chain->tile, tmp_chain->index, cur_tmpl->cargo_type | cur_tmpl->cargo_subtype << 8 | 1 << 16 | (1 << 5), flags, cb); - // old - // CopyWagonStatus(cur_tmpl, tmp_chain); + DoCommand(tmp_chain->tile, tmp_chain->index, cur_tmpl->cargo_type | (cur_tmpl->cargo_subtype << 8) | (1 << 16) | (1 << 5), flags, cb); } else { uint32 cb = GetCmdRefitVeh(tmp_chain); - DoCommand(tmp_chain->tile, tmp_chain->index, store_refit_ct | store_refit_csubt << 8 | 1 << 16 | (1 << 5), flags, cb); + DoCommand(tmp_chain->tile, tmp_chain->index, store_refit_ct | (store_refit_csubt << 8) | (1 << 16) | (1 << 5), flags, cb); } } cur_tmpl = cur_tmpl->GetNextUnit(); @@ -4424,18 +4423,21 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3 CmdRefitTrainFromTemplate(new_chain, tv, flags); } - if (new_chain && remainder_chain) - for (Train *ct = remainder_chain; ct; ct = ct->GetNextUnit()) + if (new_chain && remainder_chain) { + for (Train *ct = remainder_chain; ct; ct = ct->GetNextUnit()) { TransferCargoForTrain(ct, new_chain); + } + } // point incoming to the newly created train so that starting/stopping from the calling function can be done incoming = new_chain; - if (!stayInDepot && flags == DC_EXEC) + if (!stayInDepot && flags == DC_EXEC) { new_chain->vehstatus &= ~VS_STOPPED; + } - if (remainder_chain && keepRemainders && flags == DC_EXEC) + if (remainder_chain && keepRemainders && flags == DC_EXEC) { BreakUpRemainders(remainder_chain); - else if (remainder_chain) { + } else if (remainder_chain) { buy.AddCost(DoCommand(tile, remainder_chain->index | (1 << 20), 0, flags, CMD_SELL_VEHICLE)); } diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 139fe559eb..2f49bc6155 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -52,13 +52,12 @@ #include "gamelog.h" #include "linkgraph/linkgraph.h" #include "linkgraph/refresh.h" +#include "tbtr_template_vehicle_func.h" #include "table/strings.h" #include "safeguards.h" -#include "tbtr_template_vehicle_func.h" - #define GEN_HASH(x, y) ((GB((y), 6 + ZOOM_LVL_SHIFT, 6) << 6) + GB((x), 7 + ZOOM_LVL_SHIFT, 6)) VehicleID _new_vehicle_id; @@ -840,22 +839,21 @@ void VehicleEnteredDepotThisTick(Vehicle *v) /* Template Replacement Setup stuff */ bool stayInDepot = v->current_order.GetDepotActionType(); TemplateReplacement *tr = GetTemplateReplacementByGroupID(v->group_id); - if ( tr ) { - if ( stayInDepot ) _vehicles_to_templatereplace[(Train*)v] = true; - else _vehicles_to_templatereplace[(Train*)v] = false; - } - /* Moved the assignment for auto replacement here to prevent auto replacement - * from happening if template replacement is also scheduled */ - else + if (tr != NULL) { + _vehicles_to_templatereplace[(Train*) v] = stayInDepot; + } else { + /* Moved the assignment for auto replacement here to prevent auto replacement + * from happening if template replacement is also scheduled */ + /* Vehicle should stop in the depot if it was in 'stopping' state */ _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED); + } /* We ALWAYS set the stopped state. Even when the vehicle does not plan on * stopping in the depot, so we stop it to ensure that it will not reserve * the path out of the depot before we might autoreplace it to a different * engine. The new engine would not own the reserved path we store that we * stopped the vehicle, so autoreplace can start it again */ - v->vehstatus |= VS_STOPPED; } @@ -1024,7 +1022,6 @@ void CallVehicleTicks() /* do Template Replacement */ Backup tmpl_cur_company(_current_company, FILE_LINE); for (TemplateReplacementMap::iterator it = _vehicles_to_templatereplace.Begin(); it != _vehicles_to_templatereplace.End(); it++) { - Train *t = it->first; tmpl_cur_company.Change(t->owner); diff --git a/src/vehicle_base.h b/src/vehicle_base.h index da9cce3639..d920246a43 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -117,7 +117,7 @@ enum GroundVehicleSubtypeFlags { GVSF_ENGINE = 3, ///< Engine that can be front engine, but might be placed behind another engine (not used for road vehicles). GVSF_FREE_WAGON = 4, ///< First in a wagon chain (in depot) (not used for road vehicles). GVSF_MULTIHEADED = 5, ///< Engine is multiheaded (not used for road vehicles). - GVSF_VIRTUAL = 6, ///< Used for virtual trains during template design, it is needed to skip checks for tile or depot status + GVSF_VIRTUAL = 6, ///< Used for virtual trains during template design, it is needed to skip checks for tile or depot status }; /** Cached often queried values common to all vehicles. */ @@ -517,7 +517,7 @@ public: Money GetDisplayProfitLastYear() const { return (this->profit_last_year >> 8); } void SetNext(Vehicle *next); - inline void SetFirst(Vehicle *f) { this->first=f; } + inline void SetFirst(Vehicle *f) { this->first = f; } /** * Get the next vehicle of this vehicle. diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index fc817bc213..622cf0d562 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -426,8 +426,8 @@ static CommandCost RefitVehicle(Vehicle *v, bool only_this, uint8 num_vehicles, * @param p1 vehicle ID to refit * @param p2 various bitstuffed elements * - p2 = (bit 0-4) - New cargo type to refit to. + * - p2 = (bit 5) - Is a virtual train (used by template replacement to allow refitting without stopped-in-depot checks) * - p2 = (bit 6) - Automatic refitting. - * - p2 = (bit 5) - Is a virtual train (used by template replacement to allow refitting without stopped-in-depot checks) * - p2 = (bit 7) - Refit only this vehicle. Used only for cloning vehicles. * - p2 = (bit 8-15) - New cargo subtype to refit to. 0xFF means to try keeping the same subtype according to GetBestFittingSubType(). * - p2 = (bit 16-23) - Number of vehicles to refit (not counting articulated parts). Zero means all vehicles. @@ -457,8 +457,10 @@ CommandCost CmdRefitVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint if (v != front && (v->type == VEH_SHIP || v->type == VEH_AIRCRAFT)) return CMD_ERROR; /* Allow auto-refitting only during loading and normal refitting only in a depot. */ - if ( ! is_virtual_train ) { - if (!free_wagon && (!auto_refit || !front->current_order.IsType(OT_LOADING)) && !front->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type); + if (!is_virtual_train) { + if (!free_wagon && (!auto_refit || !front->current_order.IsType(OT_LOADING)) && !front->IsStoppedInDepot()) { + return_cmd_error(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type); + } if (front->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_VEHICLE_IS_DESTROYED); } if ((flags & DC_QUERY_COST) == 0 && // used by the refit GUI, including the order refit GUI. @@ -511,8 +513,11 @@ CommandCost CmdRefitVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0); } /* virtual vehicles get their cargo changed by the TemplateCreateWindow, so set this dirty instead of a depot window */ - if ( HasBit(v->subtype, GVSF_VIRTUAL) ) SetWindowClassesDirty(WC_CREATE_TEMPLATE); - else SetWindowDirty(WC_VEHICLE_DEPOT, front->tile); + if (HasBit(v->subtype, GVSF_VIRTUAL)) { + SetWindowClassesDirty(WC_CREATE_TEMPLATE); + } else { + SetWindowDirty(WC_VEHICLE_DEPOT, front->tile); + } } else { /* Always invalidate the cache; querycost might have filled it. */ v->InvalidateNewGRFCacheOfChain(); @@ -825,8 +830,9 @@ CommandCost CmdToggleReuseDepotVehicles(TileIndex tile, DoCommandFlag flags, uin // Identify template to toggle TemplateVehicle *template_vehicle = TemplateVehicle::GetIfValid(p1); - if (template_vehicle == NULL) + if (template_vehicle == NULL) { return CMD_ERROR; + } bool should_execute = (flags & DC_EXEC) != 0; @@ -853,8 +859,9 @@ CommandCost CmdToggleKeepRemainingVehicles(TileIndex tile, DoCommandFlag flags, // Identify template to toggle TemplateVehicle *template_vehicle = TemplateVehicle::GetIfValid(p1); - if (template_vehicle == NULL) + if (template_vehicle == NULL) { return CMD_ERROR; + } bool should_execute = (flags & DC_EXEC) != 0; @@ -881,8 +888,9 @@ CommandCost CmdToggleRefitAsTemplate(TileIndex tile, DoCommandFlag flags, uint32 // Identify template to toggle TemplateVehicle *template_vehicle = TemplateVehicle::GetIfValid(p1); - if (template_vehicle == NULL) + if (template_vehicle == NULL) { return CMD_ERROR; + } bool should_execute = (flags & DC_EXEC) != 0; @@ -910,16 +918,18 @@ CommandCost CmdVirtualTrainFromTemplateVehicle(TileIndex tile, DoCommandFlag fla TemplateVehicle* tv = TemplateVehicle::GetIfValid(template_vehicle_id); - if (tv == NULL) + if (tv == NULL) { return CMD_ERROR; + } bool should_execute = (flags & DC_EXEC) != 0; if (should_execute) { Train* train = VirtualTrainFromTemplateVehicle(tv); - if (train == nullptr) + if (train == NULL) { return CMD_ERROR; + } } return CommandCost(); @@ -931,16 +941,16 @@ Train* VirtualTrainFromTemplateVehicle(TemplateVehicle* tv) Train *tmp, *head, *tail; head = CmdBuildVirtualRailVehicle(tv->engine_type); - if ( !head ) return nullptr; + if (!head) return NULL; tail = head; tv = tv->GetNextUnit(); - while ( tv ) { + while (tv) { tmp = CmdBuildVirtualRailVehicle(tv->engine_type); - if ( tmp ) { + if (tmp) { tmp->cargo_type = tv->cargo_type; tmp->cargo_subtype = tv->cargo_subtype; - CmdMoveRailVehicle(INVALID_TILE, DC_EXEC, (1<<21) | tmp->index, tail->index, 0); + CmdMoveRailVehicle(INVALID_TILE, DC_EXEC, (1 << 21) | tmp->index, tail->index, 0); tail = tmp; } tv = tv->GetNextUnit(); @@ -965,8 +975,9 @@ CommandCost CmdVirtualTrainFromTrain(TileIndex tile, DoCommandFlag flags, uint32 VehicleID vehicle_id = p1; Vehicle* vehicle = Vehicle::GetIfValid(vehicle_id); - if (vehicle == nullptr || vehicle->type != VEH_TRAIN) + if (vehicle == NULL || vehicle->type != VEH_TRAIN) { return CMD_ERROR; + } Train* train = Train::From(vehicle); @@ -977,16 +988,16 @@ CommandCost CmdVirtualTrainFromTrain(TileIndex tile, DoCommandFlag flags, uint32 Train *tmp, *head, *tail; head = CmdBuildVirtualRailVehicle(train->engine_type); - if ( !head ) return CMD_ERROR; + if (!head) return CMD_ERROR; tail = head; train = train->GetNextUnit(); - while ( train ) { + while (train) { tmp = CmdBuildVirtualRailVehicle(train->engine_type); - if ( tmp ) { + if (tmp) { tmp->cargo_type = train->cargo_type; tmp->cargo_subtype = train->cargo_subtype; - CmdMoveRailVehicle(0, DC_EXEC, (1<<21) | tmp->index, tail->index, 0); + CmdMoveRailVehicle(0, DC_EXEC, (1 << 21) | tmp->index, tail->index, 0); tail = tmp; } train = train->GetNextUnit(); @@ -1013,8 +1024,9 @@ CommandCost CmdDeleteVirtualTrain(TileIndex tile, DoCommandFlag flags, uint32 p1 Vehicle* vehicle = Vehicle::GetIfValid(vehicle_id); - if (vehicle == nullptr || vehicle->type != VEH_TRAIN) + if (vehicle == NULL || vehicle->type != VEH_TRAIN) { return CMD_ERROR; + } Train* train = Train::From(vehicle); @@ -1044,8 +1056,9 @@ CommandCost CmdReplaceTemplateVehicle(TileIndex tile, DoCommandFlag flags, uint3 TemplateVehicle* template_vehicle = TemplateVehicle::GetIfValid(template_vehicle_id); Vehicle* vehicle = Vehicle::GetIfValid(virtual_train_id); - if (vehicle == nullptr || vehicle->type != VEH_TRAIN) + if (vehicle == NULL || vehicle->type != VEH_TRAIN) { return CMD_ERROR; + } Train* train = Train::From(vehicle); @@ -1054,16 +1067,17 @@ CommandCost CmdReplaceTemplateVehicle(TileIndex tile, DoCommandFlag flags, uint3 if (should_execute) { VehicleID old_ID = INVALID_VEHICLE; - if (template_vehicle != nullptr) { + if (template_vehicle != NULL) { old_ID = template_vehicle->index; delete template_vehicle; - template_vehicle = nullptr; + template_vehicle = NULL; } template_vehicle = TemplateVehicleFromVirtualTrain(train); - if (template_vehicle == nullptr) + if (template_vehicle == NULL) { return CMD_ERROR; + } // Make sure our replacements still point to the correct thing. if (old_ID != template_vehicle->index) { @@ -1098,20 +1112,21 @@ CommandCost CmdTemplateVehicleFromTrain(TileIndex tile, DoCommandFlag flags, uin Vehicle *t = Vehicle::GetIfValid(p1); Train *clicked = Train::GetIfValid(t->index); - if (!clicked) - return CMD_ERROR; + if (!clicked) return CMD_ERROR; Train *init_clicked = clicked; int len = CountVehiclesInChain(clicked); - if (!TemplateVehicle::CanAllocateItem(len)) + if (!TemplateVehicle::CanAllocateItem(len)) { return CMD_ERROR; + } bool should_execute = (flags & DC_EXEC) != 0; if (should_execute) { - TemplateVehicle *tmp, *prev=0; - for (; clicked; clicked=clicked->Next()) { + TemplateVehicle *tmp; + TemplateVehicle *prev = NULL; + for (; clicked != NULL; clicked = clicked->Next()) { tmp = new TemplateVehicle(clicked->engine_type); SetupTemplateVehicleFromVirtual(tmp, prev, clicked); prev = tmp; @@ -1120,7 +1135,7 @@ CommandCost CmdTemplateVehicleFromTrain(TileIndex tile, DoCommandFlag flags, uin tmp->First()->SetRealLength(CeilDiv(init_clicked->gcache.cached_total_length * 10, TILE_SIZE)); tv = tmp->First(); - if (!tv) return CMD_ERROR; + if (!tv) return CMD_ERROR; InvalidateWindowClassesData(WC_TEMPLATEGUI_MAIN, 0); } @@ -1142,8 +1157,7 @@ CommandCost CmdDeleteTemplateVehicle(TileIndex tile, DoCommandFlag flags, uint32 // Identify template to delete TemplateVehicle *del = TemplateVehicle::GetIfValid(p1); - if (del == NULL) - return CMD_ERROR; + if (del == NULL) return CMD_ERROR; bool should_execute = (flags & DC_EXEC) != 0; @@ -1181,8 +1195,9 @@ CommandCost CmdIssueTemplateReplacement(TileIndex tile, DoCommandFlag flags, uin if (should_execute) { bool succeeded = IssueTemplateReplacement(group_id, template_id); - if (!succeeded) + if (!succeeded) { return CMD_ERROR; + } InvalidateWindowClassesData(WC_TEMPLATEGUI_MAIN, 0); } @@ -1207,8 +1222,9 @@ CommandCost CmdDeleteTemplateReplacement(TileIndex tile, DoCommandFlag flags, ui if (should_execute) { TemplateReplacement* tr = GetTemplateReplacementByGroupID(group_id); - if (tr != NULL) + if (tr != NULL) { delete tr; + } InvalidateWindowClassesData(WC_TEMPLATEGUI_MAIN, 0); } diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 9dba03481a..c3dcf96c64 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -42,6 +42,7 @@ #include "safeguards.h" + Sorting _sorting; static GUIVehicleList::SortFunction VehicleNumberSorter; @@ -952,7 +953,10 @@ struct RefitWindow : public Window { if (this->order == INVALID_VEH_ORDER_ID) { bool delete_window = this->selected_vehicle == v->index && this->num_vehicles == UINT8_MAX; - if (DoCommandP(v->tile, this->selected_vehicle, this->cargo->cargo | this->cargo->subtype << 8 | this->num_vehicles << 16 | this->is_virtual_train << 5, GetCmdRefitVeh(v)) && delete_window) delete this; + if (DoCommandP(v->tile, this->selected_vehicle, this->cargo->cargo | this->cargo->subtype << 8 | this->num_vehicles << 16 | this->is_virtual_train << 5, + GetCmdRefitVeh(v)) && delete_window) { + delete this; + } } else { if (DoCommandP(v->tile, v->index, this->cargo->cargo | this->cargo->subtype << 8 | this->order << 16 | this->is_virtual_train << 5, CMD_ORDER_REFIT)) delete this; } diff --git a/src/viewport.cpp b/src/viewport.cpp index 2b3fe6e272..2c353c7252 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -2192,7 +2192,7 @@ bool HandleViewportClicked(const ViewPort *vp, int x, int y) WindowClass wc = _thd.GetCallbackWnd()->window_class; if (_ctrl_pressed && v->owner == _local_company) { StartStopVehicle(v, true); - } else if ( wc != WC_CREATE_TEMPLATE && wc != WC_TEMPLATEGUI_MAIN) { + } else if (wc != WC_CREATE_TEMPLATE && wc != WC_TEMPLATEGUI_MAIN) { ShowVehicleViewWindow(v); } } diff --git a/src/widgets/build_vehicle_widget.h b/src/widgets/build_vehicle_widget.h index 110a995578..ae548587e2 100644 --- a/src/widgets/build_vehicle_widget.h +++ b/src/widgets/build_vehicle_widget.h @@ -26,7 +26,6 @@ enum BuildVehicleWidgets { WID_BV_SHOW_HIDE, ///< Button to hide or show the selected engine. WID_BV_BUILD_SEL, ///< Build button. WID_BV_RENAME, ///< Rename button. - BUILD_VEHICLE_WIDGET_BUILD, /// TODO: own }; #endif /* WIDGETS_BUILD_VEHICLE_WIDGET_H */ From 1ebd0af2c61f51cfca0547ca9602a0ffecde179f Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 13 Feb 2016 20:44:11 +0000 Subject: [PATCH 07/15] Only include TBTR debug functions when debugging enabled. Add an initial prefix for clarity. Fix log print format codes. --- src/tbtr_template_vehicle_func.cpp | 61 +++++++++++++++++------------- src/tbtr_template_vehicle_func.h | 11 ++++-- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/tbtr_template_vehicle_func.cpp b/src/tbtr_template_vehicle_func.cpp index 087d48ea57..7064659296 100644 --- a/src/tbtr_template_vehicle_func.cpp +++ b/src/tbtr_template_vehicle_func.cpp @@ -45,43 +45,50 @@ Vehicle *vhead, *vtmp; static const uint MAX_ARTICULATED_PARTS = 100; - +#ifdef _DEBUG // debugging printing functions for convenience, usually called from gdb -void pat() { +void tbtr_debug_pat() +{ TemplateVehicle *tv; FOR_ALL_TEMPLATES(tv) { - if ( tv->Prev() ) continue; - ptv(tv); + if (tv->Prev()) continue; + tbtr_debug_ptv(tv); printf("__________\n"); } } -void pav() { - Train *t; - FOR_ALL_TRAINS(t) { - if ( t->Previous() ) continue; - pvt(t); - printf("__________\n"); - } -} -void ptv(TemplateVehicle* tv) { - if (!tv) return; - while (tv->Next() ) { - printf("eid:%3d st:%2d tv:%x next:%x cargo: %d cargo_sub: %d\n", tv->engine_type, tv->subtype, tv, tv->Next(), tv->cargo_type, tv->cargo_subtype); - tv = tv->Next(); - } - printf("eid:%3d st:%2d tv:%x next:%x cargo: %d cargo_sub: %d\n", tv->engine_type, tv->subtype, tv, tv->Next(), tv->cargo_type, tv->cargo_subtype); -} -void pvt (const Train *printme) { - for ( const Train *tmp = printme; tmp; tmp=tmp->Next() ) { - if ( tmp->index <= 0 ) { - printf("train has weird index: %d %d %x\n", tmp->index, tmp->engine_type, (__int64)tmp); - return; - } - printf("eid:%3d index:%2d subtype:%2d vehstat: %d cargo_t: %d cargo_sub: %d ref:%x\n", tmp->engine_type, tmp->index, tmp->subtype, tmp->vehstatus, tmp->cargo_type, tmp->cargo_subtype, tmp); +void tbtr_debug_pav() +{ + Train *t; + FOR_ALL_TRAINS(t) { + if (t->Previous()) continue; + tbtr_debug_pvt(t); + printf("__________\n"); } } +void tbtr_debug_ptv(TemplateVehicle* tv) +{ + if (!tv) return; + while (tv->Next() ) { + printf("eid:%3d st:%2d tv:%p next:%p cargo: %d cargo_sub: %d\n", tv->engine_type, tv->subtype, tv, tv->Next(), tv->cargo_type, tv->cargo_subtype); + tv = tv->Next(); + } + printf("eid:%3d st:%2d tv:%p next:%p cargo: %d cargo_sub: %d\n", tv->engine_type, tv->subtype, tv, tv->Next(), tv->cargo_type, tv->cargo_subtype); +} + +void tbtr_debug_pvt (const Train *printme) +{ + for (const Train *tmp = printme; tmp; tmp = tmp->Next()) { + if (tmp->index <= 0) { + printf("train has weird index: %d %d %p\n", tmp->index, tmp->engine_type, tmp); + return; + } + printf("eid:%3d index:%2d subtype:%2d vehstat: %d cargo_t: %d cargo_sub: %d ref:%p\n", tmp->engine_type, tmp->index, tmp->subtype, tmp->vehstatus, tmp->cargo_type, tmp->cargo_subtype, tmp); + } +} +#endif + void BuildTemplateGuiList(GUITemplateList *list, Scrollbar *vscroll, Owner oid, RailType railtype) { list->Clear(); diff --git a/src/tbtr_template_vehicle_func.h b/src/tbtr_template_vehicle_func.h index b2900374b4..0e2989ec87 100644 --- a/src/tbtr_template_vehicle_func.h +++ b/src/tbtr_template_vehicle_func.h @@ -48,11 +48,14 @@ Train* DeleteVirtualTrain(Train*, Train *); CommandCost CmdTemplateReplaceVehicle(Train*, bool, DoCommandFlag); -void pat(); -void pav(); -void ptv(TemplateVehicle*); -void pvt(const Train*); +#ifdef _DEBUG // for testing +void tbtr_debug_pat(); +void tbtr_debug_pav(); +void tbtr_debug_ptv(TemplateVehicle*); +void tbtr_debug_pvt(const Train*); +#endif + TemplateVehicle* GetTemplateVehicleByGroupID(GroupID); bool ChainContainsVehicle(Train*, Train*); Train* ChainContainsEngine(EngineID, Train*); From faa72e9615930e82fae995a633a4b3cf3754ea31 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 14 Feb 2016 02:55:55 +0000 Subject: [PATCH 08/15] Only show template replacement menu item where sensible. Fix drop-down not being sized for template replacement item to fit. --- src/group_gui.cpp | 4 ++-- src/vehicle_gui.cpp | 20 ++++++++++++++------ src/vehicle_gui_base.h | 4 ++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/group_gui.cpp b/src/group_gui.cpp index e286f879e0..0bee1b13ec 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -398,7 +398,7 @@ public: break; case WID_GL_MANAGE_VEHICLES_DROPDOWN: { - Dimension d = this->GetActionDropdownSize(true, true); + Dimension d = this->GetActionDropdownSize(true, true, this->vli.vtype == VEH_TRAIN); d.height += padding.height; d.width += padding.width; *size = maxdim(*size, d); @@ -657,7 +657,7 @@ public: break; case WID_GL_MANAGE_VEHICLES_DROPDOWN: { - DropDownList *list = this->BuildActionDropdownList(true, Group::IsValidID(this->vli.index)); + DropDownList *list = this->BuildActionDropdownList(true, Group::IsValidID(this->vli.index), this->vli.vtype == VEH_TRAIN); ShowDropDownList(this, list, 0, WID_GL_MANAGE_VEHICLES_DROPDOWN); break; } diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index c3dcf96c64..e914ed0451 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -143,11 +143,14 @@ void BaseVehicleListWindow::BuildVehicleList() * @param show_group If true include group-related stuff. * @return Required size. */ -Dimension BaseVehicleListWindow::GetActionDropdownSize(bool show_autoreplace, bool show_group) +Dimension BaseVehicleListWindow::GetActionDropdownSize(bool show_autoreplace, bool show_group, bool show_template_replace) { Dimension d = {0, 0}; if (show_autoreplace) d = maxdim(d, GetStringBoundingBox(STR_VEHICLE_LIST_REPLACE_VEHICLES)); + if (show_autoreplace && show_template_replace) { + d = maxdim(d, GetStringBoundingBox(STR_TMPL_TEMPLATE_REPLACEMENT)); + } d = maxdim(d, GetStringBoundingBox(STR_VEHICLE_LIST_SEND_FOR_SERVICING)); d = maxdim(d, GetStringBoundingBox(this->vehicle_depot_name[this->vli.vtype])); @@ -165,12 +168,14 @@ Dimension BaseVehicleListWindow::GetActionDropdownSize(bool show_autoreplace, bo * @param show_group If true include group-related stuff. * @return Itemlist for dropdown */ -DropDownList *BaseVehicleListWindow::BuildActionDropdownList(bool show_autoreplace, bool show_group) +DropDownList *BaseVehicleListWindow::BuildActionDropdownList(bool show_autoreplace, bool show_group, bool show_template_replace) { DropDownList *list = new DropDownList(); - *list->Append() = new DropDownListStringItem(STR_TMPL_TEMPLATE_REPLACEMENT, ADI_TEMPLATE_REPLACE, false); if (show_autoreplace) *list->Append() = new DropDownListStringItem(STR_VEHICLE_LIST_REPLACE_VEHICLES, ADI_REPLACE, false); + if (show_autoreplace && show_template_replace) { + *list->Append() = new DropDownListStringItem(STR_TMPL_TEMPLATE_REPLACEMENT, ADI_TEMPLATE_REPLACE, false); + } *list->Append() = new DropDownListStringItem(STR_VEHICLE_LIST_SEND_FOR_SERVICING, ADI_SERVICE, false); *list->Append() = new DropDownListStringItem(this->vehicle_depot_name[this->vli.vtype], ADI_DEPOT, false); @@ -1520,7 +1525,7 @@ public: } case WID_VL_MANAGE_VEHICLES_DROPDOWN: { - Dimension d = this->GetActionDropdownSize(this->vli.type == VL_STANDARD, false); + Dimension d = this->GetActionDropdownSize(this->vli.type == VL_STANDARD, false, this->vli.vtype == VEH_TRAIN); d.height += padding.height; d.width += padding.width; *size = maxdim(*size, d); @@ -1645,7 +1650,8 @@ public: break; case WID_VL_MANAGE_VEHICLES_DROPDOWN: { - DropDownList *list = this->BuildActionDropdownList(VehicleListIdentifier(this->window_number).type == VL_STANDARD, false); + DropDownList *list = this->BuildActionDropdownList(VehicleListIdentifier(this->window_number).type == VL_STANDARD, + false, this->vli.vtype == VEH_TRAIN); ShowDropDownList(this, list, 0, WID_VL_MANAGE_VEHICLES_DROPDOWN); break; } @@ -1671,7 +1677,9 @@ public: ShowReplaceGroupVehicleWindow(ALL_GROUP, this->vli.vtype); break; case ADI_TEMPLATE_REPLACE: - ShowTemplateReplaceWindow(this->unitnumber_digits, this->resize.step_height); + if (vli.vtype == VEH_TRAIN) { + ShowTemplateReplaceWindow(this->unitnumber_digits, this->resize.step_height); + } break; case ADI_SERVICE: // Send for servicing case ADI_DEPOT: // Send to Depots diff --git a/src/vehicle_gui_base.h b/src/vehicle_gui_base.h index 6bbb952882..3b7a4a2884 100644 --- a/src/vehicle_gui_base.h +++ b/src/vehicle_gui_base.h @@ -47,8 +47,8 @@ struct BaseVehicleListWindow : public Window { void DrawVehicleListItems(VehicleID selected_vehicle, int line_height, const Rect &r) const; void SortVehicleList(); void BuildVehicleList(); - Dimension GetActionDropdownSize(bool show_autoreplace, bool show_group); - DropDownList *BuildActionDropdownList(bool show_autoreplace, bool show_group); + Dimension GetActionDropdownSize(bool show_autoreplace, bool show_group, bool show_template_replace); + DropDownList *BuildActionDropdownList(bool show_autoreplace, bool show_group, bool show_template_replace); }; uint GetVehicleListHeight(VehicleType type, uint divisor = 1); From b74790187af78e11c1d145febd52a2dceb00a3f9 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 14 Feb 2016 03:04:53 +0000 Subject: [PATCH 09/15] Fix tbtr refit button crashing if new template window is empty. --- src/tbtr_template_gui_create.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tbtr_template_gui_create.cpp b/src/tbtr_template_gui_create.cpp index 741b840716..79f8a808af 100644 --- a/src/tbtr_template_gui_create.cpp +++ b/src/tbtr_template_gui_create.cpp @@ -244,7 +244,9 @@ public: break; } case TCW_REFIT: { - ShowVehicleRefitWindow(virtual_train, INVALID_VEH_ORDER_ID, this, false, true); + if (virtual_train != NULL) { + ShowVehicleRefitWindow(virtual_train, INVALID_VEH_ORDER_ID, this, false, true); + } break; } } From e8301b1bb1a981f9aa94caa1561b955062f8bac9 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 14 Feb 2016 03:23:41 +0000 Subject: [PATCH 10/15] Disable/enable buttons as selections change in TBTR main window. --- src/tbtr_template_gui_main.cpp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/tbtr_template_gui_main.cpp b/src/tbtr_template_gui_main.cpp index 4d90390502..762f7a0063 100644 --- a/src/tbtr_template_gui_main.cpp +++ b/src/tbtr_template_gui_main.cpp @@ -85,8 +85,7 @@ enum TemplateReplaceWindowWidgets { TRW_WIDGET_TMPL_BUTTONS_EDIT, TRW_WIDGET_TMPL_BUTTONS_CLONE, TRW_WIDGET_TMPL_BUTTONS_DELETE, - //TRW_WIDGET_TMPL_BUTTONS_RPLALL, - TRW_WIDGET_TMPL_BUTTON_FLUFF, + TRW_WIDGET_TMPL_BUTTONS_EDIT_RIGHTPANEL, TRW_WIDGET_TITLE_INFO_GROUP, @@ -234,6 +233,8 @@ public: this->selected_template_index = -1; this->selected_group_index = -1; + this->UpdateButtonState(); + this->templateNotice = false; this->editInProgress = false; @@ -437,6 +438,7 @@ public: } else if (newindex < this->groups.Length()) { this->selected_group_index = newindex; } + this->UpdateButtonState(); break; } case TRW_WIDGET_BOTTOM_MATRIX: { @@ -446,6 +448,7 @@ public: } else if (newindex < templates.Length()) { this->selected_template_index = newindex; } + this->UpdateButtonState(); break; } case TRW_WIDGET_START: { @@ -455,6 +458,7 @@ public: int current_group_index = (this->groups)[this->selected_group_index]->index; DoCommandP(0, current_group_index, tv_index, CMD_ISSUE_TEMPLATE_REPLACEMENT, NULL); + this->UpdateButtonState(); } break; } @@ -466,6 +470,7 @@ public: int current_group_index = (this->groups)[this->selected_group_index]->index; DoCommandP(0, current_group_index, 0, CMD_DELETE_TEMPLATE_REPLACEMENT, NULL); + this->UpdateButtonState(); break; } this->SetDirty(); @@ -526,6 +531,7 @@ public: { this->groups.ForceRebuild(); this->templates.ForceRebuild(); + this->UpdateButtonState(); } /** For a given group (id) find the template that is issued for template replacement for this group and return this template's index @@ -768,6 +774,27 @@ public: _cur_dpi = old_dpi; } + + void UpdateButtonState() + { + bool selected_ok = (this->selected_template_index >= 0) && (this->selected_template_index < (short)this->templates.Length()); + bool group_ok = (this->selected_group_index >= 0) && (this->selected_group_index < (short)this->groups.Length()); + + short g_id = -1; + if (group_ok) { + const Group *g = (this->groups)[this->selected_group_index]; + g_id = g->index; + } + + this->SetWidgetDisabledState(TRW_WIDGET_TMPL_BUTTONS_EDIT, !selected_ok); + this->SetWidgetDisabledState(TRW_WIDGET_TMPL_BUTTONS_DELETE, !selected_ok); + this->SetWidgetDisabledState(TRW_WIDGET_TMPL_BUTTONS_CONFIGTMPL_REUSE, !selected_ok); + this->SetWidgetDisabledState(TRW_WIDGET_TMPL_BUTTONS_CONFIGTMPL_KEEP, !selected_ok); + this->SetWidgetDisabledState(TRW_WIDGET_TMPL_BUTTONS_CONFIGTMPL_REFIT, !selected_ok); + + this->SetWidgetDisabledState(TRW_WIDGET_START, !(selected_ok && group_ok && FindTemplateIndexForGroup(g_id) != this->selected_template_index)); + this->SetWidgetDisabledState(TRW_WIDGET_STOP, !(group_ok && GetTemplateReplacementByGroupID(g_id) != NULL)); + } }; void ShowTemplateReplaceWindow(byte dig, int step_h) From a92268a25c6601cda69a45585c65bf8d0f90699e Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 14 Feb 2016 03:28:55 +0000 Subject: [PATCH 11/15] Attach reuse/refit/etc text to right edge of TBTR main window. --- src/tbtr_template_gui_main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tbtr_template_gui_main.cpp b/src/tbtr_template_gui_main.cpp index 762f7a0063..afd63da94c 100644 --- a/src/tbtr_template_gui_main.cpp +++ b/src/tbtr_template_gui_main.cpp @@ -710,13 +710,13 @@ public: TextColour color; color = v->IsSetReuseDepotVehicles() ? TC_LIGHT_BLUE : TC_GREY; - DrawString(left + 300, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_CONFIG_USEDEPOT, color, SA_LEFT); + DrawString(right - 225, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_CONFIG_USEDEPOT, color, SA_LEFT); color = v->IsSetKeepRemainingVehicles() ? TC_LIGHT_BLUE : TC_GREY; - DrawString(left + 400, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_CONFIG_KEEPREMAINDERS, color, SA_LEFT); + DrawString(right - 150, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_CONFIG_KEEPREMAINDERS, color, SA_LEFT); color = v->IsSetRefitAsTemplate() ? TC_LIGHT_BLUE : TC_GREY; - DrawString(left + 500, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_CONFIG_REFIT, color, SA_LEFT); + DrawString(right - 75, right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 2, STR_TMPL_CONFIG_REFIT, color, SA_LEFT); y += line_height; } From 2258fdac3ff5f8daf0a7b4a74eb69bf7929ca34f Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 14 Feb 2016 12:40:56 +0000 Subject: [PATCH 12/15] Disable new template refit button when no train. --- src/tbtr_template_gui_create.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/tbtr_template_gui_create.cpp b/src/tbtr_template_gui_create.cpp index 79f8a808af..9e4cce687b 100644 --- a/src/tbtr_template_gui_create.cpp +++ b/src/tbtr_template_gui_create.cpp @@ -165,6 +165,8 @@ public: } this->resize.step_height = 1; + + UpdateButtonState(); } ~TemplateCreateWindow() @@ -188,6 +190,7 @@ public: } virtual_train = train; + UpdateButtonState(); } virtual void OnResize() @@ -203,6 +206,7 @@ public: virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { virtualTrainChangedNotice = true; + UpdateButtonState(); } virtual void OnClick(Point pt, int widget, int click_count) @@ -326,6 +330,7 @@ public: if (virtualTrainChangedNotice) { this->SetDirty(); virtualTrainChangedNotice = false; + UpdateButtonState(); } } @@ -367,6 +372,7 @@ public: this->sel = INVALID_VEHICLE; this->SetDirty(); + UpdateButtonState(); break; } default: @@ -527,6 +533,12 @@ public: { virtual_train = virtual_train->First(); } + + + void UpdateButtonState() + { + this->SetWidgetDisabledState(TCW_REFIT, virtual_train == NULL); + } }; void ShowTemplateCreateWindow(TemplateVehicle *to_edit, bool *noticeParent, bool *createWindowOpen, int step_h) From 7ae0c6de5a7a4923b3409b5883826797ffba1c5b Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 14 Feb 2016 14:13:53 +0000 Subject: [PATCH 13/15] Remove TBTR replace all files, they are not used. --- projects/openttd_vs100.vcxproj | 2 - projects/openttd_vs100.vcxproj.filters | 6 - projects/openttd_vs140.vcxproj | 2 - projects/openttd_vs140.vcxproj.filters | 6 - projects/openttd_vs80.vcproj | 8 - projects/openttd_vs90.vcproj | 8 - source.list | 2 - src/tbtr_template_gui_main.h | 1 - src/tbtr_template_gui_replaceall.cpp | 553 ------------------------- src/tbtr_template_gui_replaceall.h | 17 - 10 files changed, 605 deletions(-) delete mode 100644 src/tbtr_template_gui_replaceall.cpp delete mode 100644 src/tbtr_template_gui_replaceall.h diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj index fb821113ca..200502ef78 100644 --- a/projects/openttd_vs100.vcxproj +++ b/projects/openttd_vs100.vcxproj @@ -294,13 +294,11 @@ - - diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters index f69240b51e..6423835e82 100644 --- a/projects/openttd_vs100.vcxproj.filters +++ b/projects/openttd_vs100.vcxproj.filters @@ -111,9 +111,6 @@ Source Files - - Source Files - Source Files @@ -129,9 +126,6 @@ Source Files - - Source Files - Source Files diff --git a/projects/openttd_vs140.vcxproj b/projects/openttd_vs140.vcxproj index 4dcfd5f04c..e55d31ae85 100644 --- a/projects/openttd_vs140.vcxproj +++ b/projects/openttd_vs140.vcxproj @@ -311,13 +311,11 @@ - - diff --git a/projects/openttd_vs140.vcxproj.filters b/projects/openttd_vs140.vcxproj.filters index f69240b51e..6423835e82 100644 --- a/projects/openttd_vs140.vcxproj.filters +++ b/projects/openttd_vs140.vcxproj.filters @@ -111,9 +111,6 @@ Source Files - - Source Files - Source Files @@ -129,9 +126,6 @@ Source Files - - Source Files - Source Files diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj index 1cb0a38673..dd33150fb5 100644 --- a/projects/openttd_vs80.vcproj +++ b/projects/openttd_vs80.vcproj @@ -446,10 +446,6 @@ RelativePath=".\..\src\tbtr_template_gui_create_virtualtrain.cpp" > - - @@ -470,10 +466,6 @@ RelativePath=".\..\src\tbtr_template_gui_create_virtualtrain.h" > - - diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj index 6c33ed8778..36e02cb215 100644 --- a/projects/openttd_vs90.vcproj +++ b/projects/openttd_vs90.vcproj @@ -443,10 +443,6 @@ RelativePath=".\..\src\tbtr_template_gui_create_virtualtrain.cpp" > - - @@ -467,10 +463,6 @@ RelativePath=".\..\src\tbtr_template_gui_create_virtualtrain.h" > - - diff --git a/source.list b/source.list index 431af3899d..cdf5ab80d3 100644 --- a/source.list +++ b/source.list @@ -2,13 +2,11 @@ tbtr_template_gui_main.cpp tbtr_template_gui_create.cpp tbtr_template_gui_create_virtualtrain.cpp -tbtr_template_gui_replaceall.cpp tbtr_template_vehicle.cpp tbtr_template_vehicle_func.cpp tbtr_template_gui_main.h tbtr_template_gui_create.h tbtr_template_gui_create_virtualtrain.h -tbtr_template_gui_replaceall.h tbtr_template_vehicle.h tbtr_template_vehicle_func.h diff --git a/src/tbtr_template_gui_main.h b/src/tbtr_template_gui_main.h index cae44e200f..0a42c6e8c4 100644 --- a/src/tbtr_template_gui_main.h +++ b/src/tbtr_template_gui_main.h @@ -20,7 +20,6 @@ #include "tbtr_template_vehicle.h" #include "tbtr_template_vehicle_func.h" -#include "tbtr_template_gui_replaceall.h" typedef GUIList GUIGroupList; diff --git a/src/tbtr_template_gui_replaceall.cpp b/src/tbtr_template_gui_replaceall.cpp deleted file mode 100644 index 445ded53ef..0000000000 --- a/src/tbtr_template_gui_replaceall.cpp +++ /dev/null @@ -1,553 +0,0 @@ -/* $Id$ */ - -/* - * This file is part of OpenTTD. - * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. - * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . - */ - -/** @file tbtr_template_gui_replaceall.cpp Template-based train replacement: replace all GUI. */ - -#include "stdafx.h" -#include "window_gui.h" -#include "window_func.h" - -#include "company_func.h" -#include "engine_base.h" -#include "engine_func.h" -#include "engine_gui.h" -#include "train.h" -#include "strings_func.h" -#include "vehicle_base.h" -#include "vehicle_func.h" - -#include "tbtr_template_vehicle.h" -#include "tbtr_template_vehicle_func.h" - -#include "core/math_func.hpp" -#include "table/strings.h" -#include "tbtr_template_gui_replaceall.h" - -#include - -#include "safeguards.h" - -/* - * A wrapper which contains a virtual train and additional info of the template vehicle it is replacing - * We will restore this additional info when creating a new template from the changed virtual train - */ -struct VirtTrainInfo { - // the virtual train - Train *vt; - - // additional info from the template - VehicleID original_index; - - bool reuse_depot_vehicles; - bool keep_remaining_vehicles; - bool refit_as_template; - - CargoID cargo_type; - byte cargo_subtype; - - // a fancy constructor - VirtTrainInfo(Train *t) { this->vt = t; } -}; - -typedef AutoFreeSmallVector VirtTrainList; -enum Widgets { - RPLALL_GUI_CAPTION, - - RPLALL_GUI_INSET_1, - RPLALL_GUI_INSET_1_1, - RPLALL_GUI_INSET_1_2, - RPLALL_GUI_MATRIX_TOPLEFT, - RPLALL_GUI_MATRIX_TOPRIGHT, - RPLALL_GUI_SCROLL_TL, - RPLALL_GUI_SCROLL_TR, - - RPLALL_GUI_INSET_2, - RPLALL_GUI_MATRIX_BOTTOM, - RPLALL_GUI_SCROLL_BO, - - RPLALL_GUI_INSET_3, - RPLALL_GUI_BUTTON_RPLALL, - RPLALL_GUI_PANEL_BUTTONFLUFF_1, - RPLALL_GUI_PANEL_BUTTONFLUFF_2, - RPLALL_GUI_BUTTON_APPLY, - RPLALL_GUI_PANEL_BUTTONFLUFF_3, - RPLALL_GUI_BUTTON_CANCEL, - - RPLALL_GUI_PANEL_RESIZEFLUFF -}; - -static const NWidgetPart widgets[] = { - // title bar - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY, RPLALL_GUI_CAPTION), SetDataTip(STR_TMPL_RPLALLGUI_TITLE, STR_TMPL_RPLALLGUI_TITLE), - NWidget(WWT_SHADEBOX, COLOUR_GREY), - NWidget(WWT_STICKYBOX, COLOUR_GREY), - EndContainer(), - // top matrices - NWidget(WWT_INSET, COLOUR_GREY, RPLALL_GUI_INSET_1), SetMinimalSize(100,12), SetResize(1,0), SetDataTip(STR_TMPL_RPLALLGUI_INSET_TOP, STR_TMPL_RPLALLGUI_INSET_TOP), EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_VERTICAL), - NWidget(WWT_INSET, COLOUR_GREY, RPLALL_GUI_INSET_1_1), SetMinimalSize(100,12), SetResize(1,0), SetDataTip(STR_TMPL_RPLALLGUI_INSET_TOP_1, STR_TMPL_RPLALLGUI_INSET_TOP_1), EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_MATRIX, COLOUR_GREY, RPLALL_GUI_MATRIX_TOPLEFT), SetMinimalSize(100, 16), SetFill(1, 1), SetResize(1, 1), SetScrollbar(RPLALL_GUI_SCROLL_TL),// SetDataTip(0x1, STR_REPLACE_HELP_LEFT_ARRAY), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, RPLALL_GUI_SCROLL_TL), - EndContainer(), - EndContainer(), - NWidget(NWID_VERTICAL), - NWidget(WWT_INSET, COLOUR_GREY, RPLALL_GUI_INSET_1_2), SetMinimalSize(100,12), SetResize(1,0), SetDataTip(STR_TMPL_RPLALLGUI_INSET_TOP_2, STR_TMPL_RPLALLGUI_INSET_TOP_2), EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_MATRIX, COLOUR_GREY, RPLALL_GUI_MATRIX_TOPRIGHT), SetMinimalSize(100, 16), SetFill(1, 1), SetResize(1, 1), SetScrollbar(RPLALL_GUI_SCROLL_TR),// SetDataTip(0x1, STR_REPLACE_HELP_LEFT_ARRAY), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, RPLALL_GUI_SCROLL_TR), - EndContainer(), - EndContainer(), - EndContainer(), - // bottom matrix - NWidget(WWT_INSET, COLOUR_GREY, RPLALL_GUI_INSET_2), SetMinimalSize(200,12), SetResize(1,0), SetDataTip(STR_TMPL_RPLALLGUI_INSET_BOTTOM, STR_TMPL_RPLALLGUI_INSET_BOTTOM), EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_MATRIX, COLOUR_GREY, RPLALL_GUI_MATRIX_BOTTOM), SetMinimalSize(200, 16), SetFill(1, 1), SetResize(1, 1), SetScrollbar(RPLALL_GUI_SCROLL_BO),// SetDataTip(0x1, STR_REPLACE_HELP_LEFT_ARRAY), - NWidget(NWID_VSCROLLBAR, COLOUR_GREY, RPLALL_GUI_SCROLL_BO), - EndContainer(), - // control area - NWidget(WWT_INSET, COLOUR_GREY, RPLALL_GUI_INSET_3), SetMinimalSize(200,12), SetResize(1,0), EndContainer(),// SetDataTip(STR_TMPL_MAINGUI_DEFINEDGROUPS, STR_TMPL_MAINGUI_DEFINEDGROUPS), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PANEL, COLOUR_GREY, RPLALL_GUI_PANEL_BUTTONFLUFF_1), SetMinimalSize(75,12), SetResize(1,0), EndContainer(), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, RPLALL_GUI_BUTTON_RPLALL), SetMinimalSize(150,12), SetResize(0,0), SetDataTip(STR_TMPL_RPLALLGUI_BUTTON_RPLALL, STR_TMPL_RPLALLGUI_BUTTON_RPLALL), - NWidget(WWT_PANEL, COLOUR_GREY, RPLALL_GUI_PANEL_BUTTONFLUFF_2), SetMinimalSize(75,12), SetResize(1,0), EndContainer(), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, RPLALL_GUI_BUTTON_APPLY), SetMinimalSize(75,12), SetResize(1,0), SetDataTip(STR_TMPL_RPLALLGUI_BUTTON_APPLY, STR_TMPL_RPLALLGUI_BUTTON_APPLY), - NWidget(WWT_PANEL, COLOUR_GREY, RPLALL_GUI_PANEL_BUTTONFLUFF_3), SetMinimalSize(150,12), SetResize(0,0), EndContainer(), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, RPLALL_GUI_BUTTON_CANCEL), SetMinimalSize(75,12), SetResize(1,0), SetDataTip(STR_TMPL_RPLALLGUI_BUTTON_CANCEL, STR_TMPL_RPLALLGUI_BUTTON_CANCEL), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PANEL, COLOUR_GREY, RPLALL_GUI_PANEL_RESIZEFLUFF), SetMinimalSize(100,12), SetResize(1,0), EndContainer(), - NWidget(WWT_RESIZEBOX, COLOUR_GREY), - EndContainer(), -}; - -static WindowDesc _template_replace_replaceall_desc( - WDP_AUTO, - "template replace window", - 400, 200, - WC_TEMPLATEGUI_RPLALL, WC_NONE, - WDF_CONSTRUCTION, - widgets, lengthof(widgets) -); - -static int CDECL EngineNumberSorter(const EngineID *a, const EngineID *b) -{ - int r = Engine::Get(*a)->list_position - Engine::Get(*b)->list_position; - - return r; -} -static int CDECL TrainEnginesThenWagonsSorter(const EngineID *a, const EngineID *b) -{ - int val_a = (RailVehInfo(*a)->railveh_type == RAILVEH_WAGON ? 1 : 0); - int val_b = (RailVehInfo(*b)->railveh_type == RAILVEH_WAGON ? 1 : 0); - int r = val_a - val_b; - - /* Use EngineID to sort instead since we want consistent sorting */ - if (r == 0) return EngineNumberSorter(a, b); - return r; -} - - -class TemplateReplacementReplaceAllWindow : public Window { -private: - uint16 line_height; - Scrollbar *vscroll_tl; - Scrollbar *vscroll_tr; - Scrollbar *vscroll_bo; - GUIEngineList *engines_left; - GUIEngineList *engines_right; - short selected_left; - short selected_right; - VirtTrainList *virtualTrains; - -public: - TemplateReplacementReplaceAllWindow(WindowDesc *wdesc) : Window(wdesc) - { - this->CreateNestedTree(wdesc != NULL); - - this->vscroll_tl = this->GetScrollbar(RPLALL_GUI_SCROLL_TL); - this->vscroll_tr = this->GetScrollbar(RPLALL_GUI_SCROLL_TR); - this->vscroll_bo = this->GetScrollbar(RPLALL_GUI_SCROLL_BO); - this->vscroll_tl->SetStepSize(16); - this->vscroll_tr->SetStepSize(16); - this->vscroll_bo->SetStepSize(16); - - this->FinishInitNested(VEH_TRAIN); - - this->owner = _local_company; - - engines_left = new GUIEngineList(); - engines_right = new GUIEngineList(); - virtualTrains = new VirtTrainList(); - - this->GenerateBuyableEnginesList(); - this->GenerateIncludedTemplateList(); - - this->line_height = 16; - this->selected_left = -1; - this->selected_right = -1; - } - - ~TemplateReplacementReplaceAllWindow() - { - for (uint i = 0; ivirtualTrains->Length(); ++i) { - delete (*this->virtualTrains)[i]->vt; - } - SetWindowClassesDirty(WC_TEMPLATEGUI_MAIN); - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case RPLALL_GUI_MATRIX_TOPLEFT: - case RPLALL_GUI_MATRIX_TOPRIGHT: - case RPLALL_GUI_MATRIX_BOTTOM: { - resize->height = 16; - size->height = 16; - break; - } - } - } - - virtual void OnPaint() - { - this->GetWidget(RPLALL_GUI_PANEL_BUTTONFLUFF_3)->colour = _company_colours[_local_company]; - - this->DrawWidgets(); - } - - virtual void OnResize() - { - NWidgetCore *nwi_tl = this->GetWidget(RPLALL_GUI_MATRIX_TOPLEFT); - this->vscroll_tl->SetCapacityFromWidget(this, RPLALL_GUI_MATRIX_TOPLEFT); - nwi_tl->widget_data = (this->vscroll_tl->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START); - - NWidgetCore *nwi_tr = this->GetWidget(RPLALL_GUI_MATRIX_TOPRIGHT); - this->vscroll_tr->SetCapacityFromWidget(this, RPLALL_GUI_MATRIX_TOPRIGHT); - nwi_tr->widget_data = (this->vscroll_tr->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START); - - NWidgetCore *nwi_bo = this->GetWidget(RPLALL_GUI_MATRIX_BOTTOM); - this->vscroll_bo->SetCapacityFromWidget(this, RPLALL_GUI_MATRIX_BOTTOM); - nwi_bo->widget_data = (this->vscroll_bo->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START); - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - switch (widget) { - case RPLALL_GUI_MATRIX_TOPLEFT: { - this->DrawEngineList(r, true); - break; - } - case RPLALL_GUI_MATRIX_TOPRIGHT: { - this->DrawEngineList(r, false); - break; - } - case RPLALL_GUI_MATRIX_BOTTOM: { - this->DrawVirtualTrains(r); - break; - } - } - } - - virtual void OnClick(Point pt, int widget, int click_count) - { - switch(widget) { - case RPLALL_GUI_MATRIX_TOPLEFT: { - uint16 newindex = (uint16)((pt.y - this->nested_array[RPLALL_GUI_MATRIX_TOPLEFT]->pos_y) / this->line_height) + this->vscroll_tl->GetPosition(); - if (newindex >= this->engines_left->Length() || newindex == this->selected_left) { - this->selected_left = -1; - } else { - this->selected_left = newindex; - } - this->SetDirty(); - break; - } - case RPLALL_GUI_MATRIX_TOPRIGHT: { - uint16 newindex = (uint16)((pt.y - this->nested_array[RPLALL_GUI_MATRIX_TOPRIGHT]->pos_y) / this->line_height) + this->vscroll_tr->GetPosition(); - if (newindex > this->engines_right->Length() || newindex==this->selected_right) { - this->selected_right = -1; - } else { - this->selected_right = newindex; - } - this->SetDirty(); - break; - } - case RPLALL_GUI_BUTTON_RPLALL: { - this->ReplaceAll(); - break; - } - case RPLALL_GUI_BUTTON_APPLY: { - // check if we actually did anything so far, if not, applying is forbidden - if (this->virtualTrains->Length() == 0) { - return; - } - // first delete all current templates - this->DeleteAllTemplateTrains(); - // then build a new list from the current virtual trains - for (uint i = 0; i < this->virtualTrains->Length(); ++i) { - // the relevant info struct - VirtTrainInfo *vti = (*this->virtualTrains)[i]; - // setup template from contained train - Train *t = vti->vt; - TemplateVehicle *tv = TemplateVehicleFromVirtualTrain(t); - // restore template specific stuff - tv->reuse_depot_vehicles = vti->reuse_depot_vehicles; - tv->keep_remaining_vehicles = vti->keep_remaining_vehicles; - tv->refit_as_template = vti->refit_as_template; - tv->cargo_type = vti->cargo_type; - tv->cargo_subtype = vti->cargo_subtype; - // use the original_index information to repoint the relevant TemplateReplacement if existing - TemplateReplacement *tr = GetTemplateReplacementByTemplateID(vti->original_index); - if (tr) { - tr->sel_template = tv->index; - } - } - // then close this window and return to parent - delete this; - break; - } - case RPLALL_GUI_BUTTON_CANCEL: { - delete this; - break; - } - } - } - - bool HasTemplateWithEngine(EngineID eid) const - { - const TemplateVehicle *tv; - FOR_ALL_TEMPLATES(tv) { - if (tv->Prev() || tv->owner != _local_company) continue; - for (const TemplateVehicle *tmp = tv; tmp != NULL; tmp = tmp->GetNextUnit()) { - if (tmp->engine_type == eid) { - return true; - } - } - } - return false; - } - - void GenerateVirtualTrains() - { - this->virtualTrains->Clear(); - - TemplateVehicle *tv; - FOR_ALL_TEMPLATES(tv) { - if (!tv->Prev() && tv->owner == this->owner) { - // setup template train - Train *newtrain = VirtualTrainFromTemplateVehicle(tv); - VirtTrainInfo *vti = new VirtTrainInfo(newtrain); - // store template specific stuff - vti->original_index = tv->index; - vti->reuse_depot_vehicles = tv->reuse_depot_vehicles; - vti->keep_remaining_vehicles = tv->keep_remaining_vehicles; - vti->refit_as_template = tv->refit_as_template; - vti->cargo_type = tv->cargo_type; - vti->cargo_subtype = tv->cargo_subtype; - // add new info struct - *this->virtualTrains->Append() = vti; - } - } - - this->vscroll_bo->SetCount(this->virtualTrains->Length()); - } - - void DeleteAllTemplateTrains() - { - TemplateVehicle *tv, *tmp; - FOR_ALL_TEMPLATES(tv) { - tmp = tv; - if (tmp->Prev() == NULL && tmp->owner == this->owner) { - delete tmp; - } - } - } - - void GenerateIncludedTemplateList() - { - int num_engines = 0; - int num_wagons = 0; - - this->engines_left->Clear(); - - const Engine *e; - FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { - EngineID eid = e->index; - const RailVehicleInfo*rvi = &e->u.rail; - - if (!HasTemplateWithEngine(eid)) continue; - - *this->engines_left->Append() = eid; - - if (rvi->railveh_type != RAILVEH_WAGON) { - num_engines++; - } else { - num_wagons++; - } - } - this->vscroll_tl->SetCount(this->engines_left->Length()); - } - - bool VirtualTrainHasEngineID(EngineID eid) - { - - for (uint i = 0; i < this->virtualTrains->Length(); ++i) { - const Train *tmp = (*this->virtualTrains)[i]->vt; - for (; tmp != NULL; tmp = tmp->Next()) { - if (tmp->engine_type == eid) { - return true; - } - } - } - return false; - } - - // after 'replace all' we need to replace the currently used templates as well - void RebuildIncludedTemplateList() { - // first remove all engine ids - for (uint i = 0; i < this->engines_left->Length(); ++i) { - EngineID entry = (*this->engines_left)[i]; - if (!VirtualTrainHasEngineID(entry)) { - this->engines_left->Erase(&((*this->engines_left)[i])); - } - } - } - - void ReplaceAll() - { - if (this->selected_left == -1 || this->selected_right == -1) return; - - EngineID eid_orig = (*this->engines_left)[this->selected_left]; - EngineID eid_repl = (*this->engines_right)[this->selected_right]; - - if (eid_orig == eid_repl) return; - - if (this->virtualTrains->Length() == 0) { - this->GenerateVirtualTrains(); - } - - for (uint i = 0; i < this->virtualTrains->Length(); ++i) { - Train *tmp = (*this->virtualTrains)[i]->vt; - while (tmp) { - if (tmp->engine_type == eid_orig) { - // build a new virtual rail vehicle and test for success - Train *nt = CmdBuildVirtualRailVehicle(eid_repl); - if (!nt) continue; - // include the (probably) new engine into the 'included'-list - this->engines_left->Include(nt->engine_type); - // advance the tmp pointer in the chain, otherwise it would get deleted later on - Train *to_del = tmp; - tmp = tmp->GetNextUnit(); - // first move the new virtual rail vehicle behind to_del - CommandCost move = CmdMoveRailVehicle(INVALID_TILE, DC_EXEC, nt->index | (1 << 21), to_del->index, 0); - // then move to_del away from the chain and delete it - move = CmdMoveRailVehicle(INVALID_TILE, DC_EXEC, to_del->index | (1 << 21), INVALID_VEHICLE, 0); - (*this->virtualTrains)[i]->vt = nt->First(); - delete to_del; - } else { - tmp = tmp->GetNextUnit(); - } - } - } - this->selected_left = -1; - // rebuild the left engines list as some engines might not be there anymore - this->RebuildIncludedTemplateList(); - this->SetDirty(); - } - - void GenerateBuyableEnginesList() - { - int num_engines = 0; - int num_wagons = 0; - - this->engines_right->Clear(); - - const Engine *e; - FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { - EngineID eid = e->index; - const RailVehicleInfo *rvi = &e->u.rail; - - if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue; - - *this->engines_right->Append() = eid; - - if (rvi->railveh_type != RAILVEH_WAGON) { - num_engines++; - } else { - num_wagons++; - } - } - - /* make engines first, and then wagons, sorted by ListPositionOfEngine() */ - EngList_Sort(this->engines_right, TrainEnginesThenWagonsSorter); - - this->vscroll_tr->SetCount(this->engines_right->Length()); - } - - void DrawEngineList(const Rect &r, bool left) const - { - uint16 y = r.top; - uint32 eid; - - Scrollbar *sb; - const GUIEngineList *el; - - if (left) { - sb = this->vscroll_tl; - el = this->engines_left; - } else { - sb = this->vscroll_tr; - el = this->engines_right; - } - - int maximum = min((int) sb->GetCapacity(), (int) el->Length()) + sb->GetPosition(); - - for (int i = sb->GetPosition(); i < maximum; ++i) { - eid = (*el)[i]; - - /* Draw a grey background rectangle if the current line is the selected one */ - if ((left && this->selected_left == i) || (!left && this->selected_right == i)) { - GfxFillRect(r.left, y, r.right, y + this->line_height, _colour_gradient[COLOUR_GREY][3]); - } - - /* Draw a description string of the current engine */ - SetDParam(0, eid); - DrawString(r.left + 100, r.right, y + 4, STR_ENGINE_NAME, TC_BLACK); - - /* Draw the engine */ - DrawVehicleEngine(r.left, r.right, r.left + 29, y + 8, eid, GetEnginePalette(eid, _local_company), EIT_PURCHASE); - - y += this->line_height; - } - } - - void DrawVirtualTrains(const Rect &r) const - { - uint16 y = r.top; - - uint16 max = min(virtualTrains->Length(), this->vscroll_bo->GetCapacity()); - - for (uint16 i = vscroll_bo->GetPosition(); i < max + vscroll_bo->GetPosition(); ++i) { - /* Draw a virtual train*/ - DrawTrainImage((*this->virtualTrains)[i]->vt, r.left + 32, r.right, y, INVALID_VEHICLE, EIT_PURCHASE, 0, -1); - - y += this->line_height; - } - } -}; - -void ShowTemplateReplaceAllGui() -{ - new TemplateReplacementReplaceAllWindow(&_template_replace_replaceall_desc); -} diff --git a/src/tbtr_template_gui_replaceall.h b/src/tbtr_template_gui_replaceall.h deleted file mode 100644 index 02d8aae2ca..0000000000 --- a/src/tbtr_template_gui_replaceall.h +++ /dev/null @@ -1,17 +0,0 @@ -/* $Id$ */ - -/* - * This file is part of OpenTTD. - * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. - * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . - */ - -/** @file tbtr_template_gui_replaceall.cpp Template-based train replacement: replace all GUI header. */ - -#ifndef TMPL_RPLALL_GUI -#define TMPL_RPLALL_GUI - -void ShowTemplateReplaceAllGui(); - -#endif From de7f1c11685d491c972079a6d0164d9a6ed007b6 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 14 Feb 2016 16:54:37 +0000 Subject: [PATCH 14/15] Show cost text effect and failure advice messages for TBTR replacement. Minor whitespace/formatting changes. --- src/train_cmd.cpp | 11 +++++----- src/vehicle.cpp | 53 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 091b638c24..5f8d9ae1f0 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -4290,11 +4290,12 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3 short store_refit_csubt = 0; // if a train shall keep its old refit, store the refit setting of its first vehicle if (!use_refit) { - for (Train *getc = incoming; getc != NULL; getc = getc->GetNextUnit()) + for (Train *getc = incoming; getc != NULL; getc = getc->GetNextUnit()) { if (getc->cargo_type != CT_INVALID) { store_refit_ct = getc->cargo_type; break; } + } } // TODO: set result status to success/no success before returning @@ -4308,7 +4309,7 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3 CommandCost buyCost = TestBuyAllTemplateVehiclesInChain(tv, tile); if (!buyCost.Succeeded() || !CheckCompanyHasMoney(buyCost)) { if (!stayInDepot) incoming->vehstatus &= ~VS_STOPPED; - return buy; + return_cmd_error(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY); } } @@ -4388,8 +4389,9 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3 // 3. must buy new engine else { tmp_result = DoCommand(tile, cur_tmpl->engine_type, 0, flags, CMD_BUILD_VEHICLE); - if (!tmp_result.Succeeded()) + if (!tmp_result.Succeeded()) { return tmp_result; + } buy.AddCost(tmp_result); tmp_chain = Train::Get(_new_vehicle_id); move_cost.AddCost(CmdMoveRailVehicle(tile, flags, tmp_chain->index, last_veh->index, 0)); @@ -4399,8 +4401,7 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3 if (use_refit) { uint32 cb = GetCmdRefitVeh(tmp_chain); DoCommand(tmp_chain->tile, tmp_chain->index, cur_tmpl->cargo_type | (cur_tmpl->cargo_subtype << 8) | (1 << 16) | (1 << 5), flags, cb); - } - else { + } else { uint32 cb = GetCmdRefitVeh(tmp_chain); DoCommand(tmp_chain->tile, tmp_chain->index, store_refit_ct | (store_refit_csubt << 8) | (1 << 16) | (1 << 5), flags, cb); } diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 2f49bc6155..9f17876dfe 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -892,6 +892,25 @@ static void RunVehicleDayProc() } } +static void ShowAutoReplaceAdviceMessage(const CommandCost &res, const Vehicle *v) +{ + StringID error_message = res.GetErrorMessage(); + if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) return; + + if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT; + + StringID message; + if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) { + message = error_message; + } else { + message = STR_NEWS_VEHICLE_AUTORENEW_FAILED; + } + + SetDParam(0, v->index); + SetDParam(1, error_message); + AddVehicleAdviceNewsItem(message, v->index); +} + void CallVehicleTicks() { _vehicles_to_autoreplace.Clear(); @@ -1001,21 +1020,7 @@ void CallVehicleTicks() continue; } - StringID error_message = res.GetErrorMessage(); - if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue; - - if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT; - - StringID message; - if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) { - message = error_message; - } else { - message = STR_NEWS_VEHICLE_AUTORENEW_FAILED; - } - - SetDParam(0, v->index); - SetDParam(1, error_message); - AddVehicleAdviceNewsItem(message, v->index); + ShowAutoReplaceAdviceMessage(res, v); } cur_company.Restore(); @@ -1024,12 +1029,28 @@ void CallVehicleTicks() for (TemplateReplacementMap::iterator it = _vehicles_to_templatereplace.Begin(); it != _vehicles_to_templatereplace.End(); it++) { Train *t = it->first; + /* Store the position of the effect as the vehicle pointer will become invalid later */ + int x = t->x_pos; + int y = t->y_pos; + int z = t->z_pos; + tmpl_cur_company.Change(t->owner); bool stayInDepot = it->second; it->first->vehstatus |= VS_STOPPED; - DoCommand(t->tile, t->index, stayInDepot ? 1 : 0, DC_EXEC, CMD_TEMPLATE_REPLACE_VEHICLE); + CommandCost res = DoCommand(t->tile, t->index, stayInDepot ? 1 : 0, DC_EXEC, CMD_TEMPLATE_REPLACE_VEHICLE); + + if (!IsLocalCompany()) continue; + + if (res.Succeeded()) { + if (res.GetCost() != 0) { + ShowCostOrIncomeAnimation(x, y, z, res.GetCost()); + } + continue; + } + + ShowAutoReplaceAdviceMessage(res, t); } tmpl_cur_company.Restore(); } From 99509acd1d0bcd606260231fdf829ee1f8e0140a Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sun, 14 Feb 2016 17:29:41 +0000 Subject: [PATCH 15/15] Extended version info for TBTR. --- src/saveload/extended_ver_sl.cpp | 1 + src/saveload/extended_ver_sl.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 6e13994e67..18890d44ca 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -45,6 +45,7 @@ std::vector _sl_xv_discardable_chunk_ids; ///< list of chunks static const uint32 _sl_xv_slxi_chunk_version = 0; ///< current version os SLXI chunk const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { + { XSLFI_TEMPLATE_REPLACEMENT, XSCF_NULL, 1, 1, "template_replacement", NULL, NULL, "TRPL,TMPL" }, { XSLFI_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker }; diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h index 39a03478c2..ebb3f38609 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -21,6 +21,7 @@ */ enum SlXvFeatureIndex { XSLFI_NULL = 0, ///< Unused value, to indicate that no extended feature test is in use + XSLFI_TEMPLATE_REPLACEMENT, ///< Template-based train replacement XSLFI_SIZE, ///< Total count of features, including null feature };