Crusader Kings III geliştirici günlüklerinde bu hafta oyunun modlanabilirliğine dair bilgiler veriliyor.
Herkese merhabalar, Crusader Kings III için kaleme alınmış 37. geliştirici günlüğüne hoş geldiniz.
Ben Matthew, Crusader Kings III ekibindeki programcılardan biriyim. Bugün sizlere Crusader Kings III’ün modlanabilirliğinden söz edeceğim.
Modlar bizim için çok önemli, benim için ise ekstra ayrı bir yönü var keza Paradox’a İçerik Tasarımcısı olarak katılmam Crusader Kings II için yaptığım bir mod sayesinde mümkün olmuştu. Şimdilerde bir zamanlar modladığım oyunun devam oyununda görev alıyorum ve bu sektöre katılmama olanak tanımış topluluğa bir teşekkür olarak oyunun modlanabilirliğine büyük önem veriyorum. Ekipte yer alan birçok diğer arkadaşımın da benimle benzer hikayelere sahip olduğunu biliyorum.
İlk olarak oyunda modlamayla değiştirilebilir unsurları genişletmeyi hedefledik. Oyunda 80’i aşkın veritabanı klasörüne sahibiz (bu klasörlerin bazıları alt klasörler dahi içeriyor), çok daha esnek bir event sistemine, tamamen değiştirilebilir bir GUI sistemine, tarih dosyalarına, yerelleştirme, ses ve müzik sistemlerine sahibiz. Anlayacağınız üzere oyunun büyük bir kısmını istekleriniz doğrultusunda değiştirebiliyorsunuz.
Günlüğün geri kalan kısmında neler yapabileceğinizden bahsedip CK2 modçularını heyecanlandıracağını düşündüğüm bazı özellikler tanıtacağım.
Imperator ve Crusader Kings III Jomini adını verdiğimiz, kendi geliştirdiğimiz bir script diline sahip. Bunu bir bakıma Clausewitz motorunun üstüne Grand Strategy odaklı bir katman daha eklenmiş gibi düşünebilirsiniz.
Imperator çıktığında direkt olarak Jomini kaynaklı olan dolayısıyla her iki oyunda da ortak bir biçimde yer alan hususlara dair bir bilgi konusu açmıştım. Eğer modlamayla ilgileniyorsanız bu konuyu okumanızı öneriyorum. Bunların yanı sıra eğer event modlamayla ilgileniyorsanız 30. geliştirici günlüğümüz sizin için önemli bilgiler içeriyor.
Karakter Etkileşimleri
CK2’ye nazaran modlamadaki en büyük değişikliklerden birisi karakter etkileşimleri üzerinde.
CK2’nin modlanabilirliğinden biraz bahsetmek gerekirse, bu etkileşimlerin büyük bir kısmı hardcode şeklinde oyuna eklenmişti. Evlilik yapmaktan savaş açmaya, ittifak kurmaktan daha birçok etkileşime kadar birçok şey modlanabilir değildi. Birkaç yama sonra “hedefli kararlar” şeklinde bir özellik eklendi. Bu özellik kabaca karakterlere modifier ekleyebilmenizi veya mevcut modifieri değiştirebilmenizi sağlıyordu, dolayısıyla hardcoded ana etkileşimler halen modlanabilir durumda değildi.
CK3’te tek bir ortak karakter etkileşim sistemine sahibiz, her etkileşim script üzerinden gerçekleşiyor. Böylelikle kodlamaya girmektense birkaç metin dosyasında değişiklik yaparak yapay zekanın hareketlerini dengeleyebiliyoruz, bu etkileşimleri kimin kullanabileceklerini vb. hususları daha kolay belirleyebiliyoruz. Tüm bu husus modcular için de geçerli.
Yapay zeka oluşturulan custom etkileşimleri kullanmak üzere de kodlanabilir, kimin iyi bir hedef olduğunu, ne sıklıkla bu etkileşimi değerlendirmesi gerektiğini belirleyebilirsiniz (performans için oldukça önemli)
Halen özellikle yapay zekanın çok elzem olmayan kullanım alanlarında çeşitli hardcoded unsurlar yer alıyor. Bu etkileşimlerin hangileri olduğu net bir şekilde işaretlenmiş durumda fakat olur da silmeye kalkarsanız oyunu açtığınızda bu etkileşime ihtiyaç duyulduğuna dair bilgilendirme mesajı alıyorsunuz. Bu durum tüm hardcoded veritabanı unsurları için geçerli.
Aşağıda yapay zekanın bir etkileşimi değerlendirirken neleri gözönünde bulundurabildiğini görebiliyorsunuz:
my_interaction = { interface_priority = number # Used by interaction menu common_interaction = yes/no # Used by interaction menu category = interaction_category_hostile # Used by interaction menu is_highlighted = trigger # Should the interaction be highlighted in the menu highlighted_reason = loc_key # Tooltip if highlighted in menu on_decline_summary = dynamic description # Flavor text that is shown under acceptance widget. Use it when you need to draw more attention to the on decline effect special_interaction = type # This interaction uses specialized GUI special_ai_interaction = type # This interaction runs specialized code that identifies the interaction by this interface = call_ally/marriage/grant_titles/etc. # What interface does the interaction use? scheme = elope/murder/etc. # The type of scheme the interaction starts popup_on_receive = yes # Have the interaction pop-up for the recipient when received force_notification = yes/no # Force diplomatic item if interaction is auto-accept pause_on_receive = yes/no # Pause the game on receive. It usually makes sense to combine it with popup_on_receive ai_accept_negotiation = yes/no # If the interaction is declined negotiations will start. We don't show "won't accept", etc. because there is still a possibility that the interaction will be accepted via negotiation event chain hidden = yes # Is the interaction hidden? use_diplomatic_range = yes/no/trigger # Does this interaction check diplomatic range? Yes by default can_send_despite_rejection = yes # Interaction can be sent and the ai might reject ignores_pending_interaction_block = yes # If the actor is a player and the recipient already has received an interaction from them pending a response, can this interaction be sent anyway. Defaults to no send_name = loc_key # The name of the interaction in context of it being seen once sent. Defaults to database object key needs_recipient_to_open = yes # Does the interaction need a recipient set to be able to be allowed to open and be shown. Defaults to no show_answer_notification = no # Does this show a response info pop up when an interaction is answered if the actor is a player. Defaults to yes show_effects_in_notification = no # Should the effects of the interaction be shown in the notification window when an interaction is sent. Defaults to yes icon = texture_path # Icon used in various places. Default is gfx/interface/icons/character_interactions/my_interaction.dds alert_icon = texture_path # Default is gfx/interface/icons/character_interactions/my_interaction_alert.dds icon_small = texture_path # Default is gfx/interface/icons/character_interactions/my_interaction_small.dds should_use_extra_icon = { always = yes } # When to show an extra icon. Tooltip key is <key>_extra_icon extra_icon = "gfx/<...>/hook_icon.dds" # Icon to show when should_use_extra_icon is true target_type = type # Possible types: title, none (default) target_filter = type # See FAQ for possible types ai_maybe = yes # The ai can reply maybe ai_min_reply_days = 4 # Minimum days before ai replies ai_max_reply_days = 9 # Maximum days before ai replies desc = loc_key # Short description of the interaction greeting = negative/positive # Sets tone in request text notification_text = loc_key # Request text prompt = loc_key # What text should be shown under the portrait? (For example: "Pick a Guardian") show_effects_in_notification = yes/no # Should the effects be shown in the notification? cooldown = { years = x } # How long until the decision can be taken again? cooldown_against_recipient = { years = x } # How long until the decision can be taken against recipient again? is_shown = trigger # Is the interaction available and visible between scope:actor and scope:recipient is_valid_showing_failures_only = trigger # Is the interaction valid to be selected in it's current setup, trigger only displays failures is_valid = trigger # Is the interaction valid to be selected in it's current setup has_valid_target_showing_failures_only = trigger # TODO has_valid_target = trigger # TODO can_be_picked = trigger # TODO can_be_picked_title = trigger # TODO auto_accept = yes/no/trigger # Is the interaction automatically accepted, or can recipient decide can_send = trigger # Can the interaction be sent can_be_blocked = trigger # Can the interaction be blocked by the recipient (i.e. by a hook on the actor) is_highlighted = trigger # Should the interaction be highlighted in the menu can_send = trigger # Can the interaction be sent? redirect = {} # This changes the redirection of characters using the scopes actor, recipient, secondary_actor and secondary_recipient populate_actor_list = {} # Everyone sorted into the list 'characters' has the potential of being shown to be selected. Uses the scopes actor, recipient, secondary_actor and secondary_recipient. populate_recipient_list = {} localization_values = = {} # To be able to use values in loc (for example: RANSOM_COST = scope:secondary_recipient.ransom_cost_value lets you use $RANSOM_COST|0$ in loc) options_heading = loc_key # Text shown above options block - describes all options in general send_option = { # Adds an option is_shown = trigger # Is option shown is_valid = trigger # Is option selectable current_description = desc # Tooltip flag = flag_name # If selected then scope:flag_name will be set to yes localization = loc_key # Loc_key for option label starts_enabled = trigger # Trigger for whether this should be on when the window opens. If not defined, defaults to off can_be_changed = trigger # Trigger for whether this option can be changed from its default can_invalidate_interaction = bool # If yes then when the AI picks an interaction it will do the full can send this entire interaction check instead of the more performance saving checking of recipient refusal and ai will do, use with care and profile it } # Options should avoid preventing an interaction from sending (except by the recipient refusing), as we assume that to be the case in the AI for performance reasons, use can_invalidate_interaction if you need it to be re-checked send_options_exclusive = yes/no # Are the options exclusive? on_send = effect # Executes directly the interaction is sent on_accept = effect # Executes when accepted by recipient on_decline = effect # Executes when declined by recipient on_blocked_effect = effect # Executes when blocked by recipient pre_auto_accept = effect # Only executes if the interaction was auto accepted. Done before any other side effect (E.G., hard coded ones like marriage) on_auto_accept = effect # Only executes if the interaction was auto accepted reply_item_key = loc_key # The key to the loc to show in the interaction item tooltip. Receives the name of the interaction in $INTERACTION$. Default value "INTERACTION_REPLY_ITEM" # These loc keys are shown to the player when sending the interaction. The meaning is what is going to be the answer from the target. pre_answer_yes_key = loc_key # The key to the loc when the interaction is going to be accepted. Default value "ANSWER_YES" pre_answer_no_key = loc_key # The key to the loc when the interaction is NOT going to be accepted. Default value "ANSWER_NO" pre_answer_maybe_key = loc_key # The key to the loc when the interaction maybe is accepted. Receives the acceptance value in $VALUE$. Default value "ANSWER_MAYBE" pre_answer_maybe_breakdown_key = loc_key # The key used to localize the chance of acceptance of an interaction with provided chance value. Defaults to ANSWER_SUM_MAYBE # These loc keys are shown to the player when answering an interaction. answer_block_key = loc_key # The key to the loc to block the interaction. Default value "ANSWER_BLOCK" answer_accept_key = loc_key # The key to the loc to accept the interaction. Default value "ANSWER_YES" answer_reject_key = loc_key # The key to the loc to reject the interaction. Default value "ANSWER_NO" answer_acknowledge_key = loc_key # The key to the loc to reject the interaction. Default value "ANSWER_ACKNOWLEDGE" cost = { # Scripted cost for the interaction. The interaction will be disabled if the actor can't pay up, and the cost will be subtracted from the actor when the interaction is sent. Renown can only be spent by the dynast. piety = {} prestige = {} gold = {} renown = {} } ai_set_target = {} # Set scope:target to make the AI target something specific. Title targeting interactions don't need this ai_targets = { ai_recipients = type # Which characters does the ai consider as recipient for the interaction, can be scripted multiple times to combine lists # Available lists are in the "ai_targets" section of this file (trying to add an invalid list will trigger an error message with all available ) chance = 0-1 # A low chance, such as 0.25, randomly excludes that number of characters from being checked - this is useful for saving performance } ai_target_quick_trigger = { # Quick triggers for the ai_targets adult = yes # The target needs to be adult attracted_to_owner = yes # The target needs to be attracted to owner owner_attracted = yes # Owner needs to be attracted to the target prison = yes # Target must be in prison } ai_frequency = months # How often should the ai consider doing this interaction ai_potential = trigger # Will the ai consider trying this interaction ai_accept = mtth # Will the ai accept a request for this interaction ai_will_do = mtth # How interested is the ai in sending this interaction (tested after selecting targets) 0-100 percent chance, will be clamped. # Note that for title interactions, each individual target title will get evaluated, and the one giving the highest ai_will_do will get used. If the interaction has options, the combination of options that gives the highest ai_will_do will be used. }Birden Fazla Mod
Birden fazla modu aynı anda aktifleştirmek ezelden beri sıkıntılar çıkartabilen bir durumdu. Bu noktada oyuncunun modlarda değişiklikler yapmasını gerektirmemek veya azaltmak adına bazı değişikliklerimiz oldu. İlk olarak veritabanı satırlarının eğer bir satır başka bir dosyada yer alıyorsa bir key aracılığıyla birbirinin üstüne yazılabilmesini sağladık. Bu demek oluyor ki Deli özelliğini değiştirmek için artık tüm kodları kopyalayıp bunun üzerinde değişiklik yapmanıza gerek yok, kendi kodunuzu yazıp örneğin aşağıda gösterdiğim gibi Öğrenim, Dövüş ve Çekicilik gibi alanlarda bonuslar verebiliyorsunuz:
Bu durum farklı modlar için de geçerli, eğer sizin modunuz önce yükleniyorsa farklı modlardaki özelliklerin veya diğer veritabanı unsurlarının üstüne yazabiliyorsunuz. Henüz tamamen üstüne yazma gibi bir özelliği desteklemiyoruz keza bunun için geniş çaplı bir çalışmanın ardından birçok şeyi test etmemiz gerekiyor fakat gelecek için aklımda tuttuğum şeylerden biri olduğunu söyleyebilirim.
Uyarılar, Sorunlar ve Bildirimler
16. geliştirici günlüğünde bahsettiğim üzere oyunu açıklama görevi gören arayüz unsurları tamamen modlanabilir. Bu durum CK2’deki gibi hardcoded olmasından ziyade her şeyi modlayabileceğiniz, yeni şeyler ekleyip değiştirebileceğiniz veya silebileceğiniz anlamına geliyor.
En basitleri onlar olduğu için bildirimler ve kadeh kaldırmalardan bahsedeceğim. Common dosyasında bildiriminiz için bir veritabanı satırı oluşturuyorsunuz, ardından bu satırın kullanım efekti olarak send_interface_message veya send_interface_toast_effect yazıyorsunuz.
Bu etkiler mesajın türünün yanı sıra veritabanındaki kodların yerine unvan ve metin yazılarını gösteriyor. Bunla birlikte istediğiniz sayıda etki aktifleştirebiliyorsunuz ve bunlar metin şeklinde gösteriliyor, elbette ciddi uzunlukta mekanik bir metin görmektense custom bilgi çubuğu oluşturmanız daha isabetli olacaktır.
Uyarılar, tavsiyeler ve mevcut sorunların hepsi “önemli eylemler” sistemi üzerinden şekilleniyor, aralarındaki en büyük fark sahip oldukları tür. Bu tür onların görünümünü ve konumunu belirliyor. Bu önemli eylemler check_create_action ve etki blokuna sahip, ikisi de arayüz etkileri (multiplayerda oyun gamestate’ini değiştirmeyen, yerel arayüz unsurları) üzerinden çalışıyor.
check_create_action için ana arayüz etkisi try_create_important_action, bu belli eylem türünde bir arayüz unsuru oluşturuyor. Etki bloku olarak eğer oyuncu hareketine göre şekillenen bir tavsiye ise start_tutorial_lesson kullanmanız daha isabetli, uyarılar ve sorunlarda open_view_data daha faydalı.
Dipnot: Bu günlüğü yazarken oyunun 1.0 sürümünde bildirimler için custom ikon modlamanın çalışmadığını fark ettim, mevzubahis sorun 1.1’de çözüldü fakat oyun çıktığında bu günlüğe gelerek çalışmadığını yazabilecek kişiler için önceden belirtme ihtiyacı hissettim.
Öneriler önemli eylemlere benzer bir şekilde çalışıyor ancak her önerinin oyuncu için ne kadar önemli olduğuna dair çeşitli değerleri bulunuyor. Örneğin hak iddiası üretme önerisi, etrafınızda hak iddiası üretebileceğiniz bir unvan varsa karşınıza çıkıyor. Burada mevzubahis unvanın gelişmişlik seviyesi, hak iddiası üretseniz bile fethedip fethedemeyeceğiniz gibi faktörler ele alınıyor.
GUI Scriptleri
Tıpkı Imperator gibi arayüz de oldukça modlanabilir vaziyette. GUI Script dili farklılıklar barındırsa da normal veritabanı ve event kodları oldukça esnek. Oyundaki neredeyse tüm arayüz unsurlarının konumlarını, görünümlerini ve kullanım alanlarını değiştirebiliyorsunuz. Aynı zamanda bir GUI debug moduna sahibiz, buradan dosyaları açıp neyin hangi satırda yer aldığını görebiliyorsunuz.
Şimdilik yeni bir GUI penceresi oluşturma özelliğimiz yok (ama bu da sonu gözükmeyen listemin bir parçası), burada yapabileceğiniz şeylerden birisi pencereyi ana HUD penceresinin altında yapmak. Jomini Modlama konusunda bahsettiğim gibi pencerelerle normal kodlamalar arasında bağlantı oluşturabiliyorsunuz, dolayısıyla farklı şeyleri denemek için bir pencere yaratıp denemeler gerçekleştirebilirsiniz.
Aşağıda farklı mezhepten yetişkinlere yönelik kullanılabilen cinayet butonumu görebilirsiniz:
Okuduğunuz için teşekkürler, bu günlüğün alıcı kitlesinin nispeten daha dar olacağının farkındayım. Eğer oynanışa dair bilgiler almak istiyorsanız önümüzdeki CK3 yayınını kaçırmayın.