User prompt
"Anlık Tepki Sistemi" Ekleyin Seçim yapıldığında, sahne değişmeden önce karakterin yüzüne veya repliğine bağlı olarak küçük bir "popup tepkisi" (örneğin Mike'ın yüz ifadesi değişir ya da iç sesi belirir) göster. Bu, oyuncuya kararının hemen bir etkisi olduğunu hissettirir.
User prompt
"Bilinmeyen Seçim" Sistemi Kur Bazı seçimlerin içeriği başlangıçta “???” olarak gizlensin. Ancak oyuncunun "honest" veya "betray" barı belirli bir seviyeye ulaştığında bu seçenek görünür hale gelsin. Bu sayede barların sadece sonuç değil, bilgi erişimi üstünde de etkisi olur.
User prompt
O aki soru kiminle alakalı ise Yukarıda Mike'ın assetinin yanına o karakteri de koy
User prompt
Bar Kırılımına Göre Animasyonlu Game Over Ekranı Yap: Örneğin, betray barı 100 olursa Mike gözaltına alınıyor, lust barı 0 olursa Lisa uzaklaşıyor gibi. Bunları sadece metinle değil, portre değişimi ve kısa animasyonlarla (fade-out, çarpı işareti vb.) sun.
User prompt
Peter ve Alex için de yap aynısını
User prompt
Duygu Durumu Göstergeleri Yerleştir: Her sahnede portreyle birlikte Lisa, Rebecca ya da Mike’ın yüz ifadesini göstermek için "mood": "angry" gibi bir alan tanımla. Bu alan, portre resmini veya arka plan rengini belirlesin. Böylece görsel duygu aktarımı sağlanır.
User prompt
‘İlişki Çaprazlama’ Mekanizması Ekle: Örneğin, Lisa’yla samimiyet kurdukça Rebecca kıskanıp ilişki barını düşürsün. Bu gibi çapraz etkileşimleri applyCrossEffects() fonksiyonunda tanımlayarak barların dinamik bir yapıya kavuşmasını sağla.
User prompt
Zamana Bağlı Tetikleyiciler Tanımla: Oyunun toplam süresini ya da kaç seçim yapıldığını sayan turnCount gibi bir sayaç ekle. Örneğin if (turnCount > 15 && bars.lust.value > 60) özel bir rüya sahnesi başlasın. Bu, oyuncuyu zamana karşı strateji kurmaya zorlar.
User prompt
“Memory” Mekaniği Getir: state.pastChoices gibi bir array’e önemli kararları (örneğin Lisa’yı öpmek, Rebecca’ya yalan söylemek) ekle. Gelecek sahnelerde bu kararlar okunarak farklı metinler sunulsun. Bu sistem, oyuncuya seçimlerinin hatırlandığını ve yankılandığını hissettirecek.
User prompt
Seçeneklere ‘yalan/doğru’ gibi gizli etiketler ekle: Seçeneklere örneğin meta: { type: "lie" } ekle. Bu bilgilerle oyuncunun sürekli yalan söylemesi durumunda honest barı kademeli düşsün. Seçeneklerdeki metinle bar etkisi arasında dolaylı ilişki kurarak oyuna derinlik kat.
User prompt
Bar Bazlı “Flag” Sistemi Kur: Bazı bar eşiklerine ulaşıldığında flags objesine bayrak ekle. Örneğin if (bars.betray.value >= 80) flags["betrayalUnlocked"] = true;. Bunlar ileride özel sahneleri veya sonları tetiklemek için kullanılabilir.
User prompt
Please fix the bug: 'characterLabels is not defined' in or related to this line: 'for (var i = 0; i < characterLabels.length; i++) {' Line Number: 883
User prompt
Bardaki Değer Artışına Göre Sahne Çoğalt: Tek bir StoryNode yerine, aynı durumun 3 versiyonunu yaz (örneğin: düşük, orta, yüksek ilişki durumlarında Lisa'nın tepkisi farklı). getNextNode() fonksiyonu bu versiyonlardan hangisinin gösterileceğini bardaki değere göre belirlesin. (e.g. if (bars.lisa.value > 80) return node.idHappyLisa;)
User prompt
Bar Bazlı Diyalog Kilitleme Sistemi Kur: Her StoryNode’a opsiyonel olarak bir requirements alanı ekle. Örneğin, requirements: { honest: 30, lisa: 50 } gibi. Eğer bu koşullar sağlanmıyorsa seçenek gizlensin ya da disabled: true olarak işaretlenip gri tonla gösterilsin. Oyuncu seçim yaparken barlarının doğrudan sonuç doğurduğunu görmeli.
User prompt
Please fix the bug: 'rel_lisa is not defined' in or related to this line: 'var chars = [{' Line Number: 726
User prompt
Bar Sistemini Karakter Bazında Ayır: Her barı belirli bir karaktere (Lisa, Rebecca, Alex vs.) bağla. Bu karakterlerin ilişkisel barlarını ayrı ayrı RelationshipBar nesneleri olarak tanımla ve effects: { lisa: 10 } gibi tanımlarda hangi barın artacağını veya azalacağını kesin biçimde kontrol et. Gerekirse bars["lisa"].setValue(...) gibi bir sistem kur.
User prompt
Sorular random ilerlesin. Aynı şeyi sorup duruyor. Çok çeşitli olsun sorular ve hep iki şık olsun. Ona göre ilerlesin hikaye
User prompt
Barlar 50 ile başlasın. yüzde 1 insin ya da çıksın sadece. Oyun hemen bitmesin. Random sorulara devam etsin. Barların yanında ne barı oldukları yazsın. Ayrıca dört karakteri assetleri ile beraber en altta göster ve ilişki derecelerini yaz.
Code edit (1 edits merged)
Please save this source code
User prompt
Mike’ın Yolu — Hikâye Tabanlı 2D Karar Oyunu
Initial prompt
Mike'ın Yolu — Hikâye Tabanlı 2D Karar Oyunu "Mike’ın Yolu", oyuncuyu bir adamın içsel çatışmaları, sosyal ilişkileri ve ahlaki seçimleri arasında geçen karmaşık bir yaşam yolculuğuna davet eden 2D hikâye tabanlı bir oyun. Bu oyun; evliliğin kırılganlığı, dostlukların dayanıklılığı, iş hayatının baskısı ve bireysel dürtüler gibi insana dair tüm yönleri sorgulamanı sağlayan bir yapıya sahip. Oyuncu, karakterimiz Mike’ın yerine geçerek her gün gelen sorulara iki seçenekten birini seçer. Bu seçimler Mike’ın yalnızca çevresiyle olan ilişkilerini değil, kendi iç dünyasını da etkiler. Oyunun temelini, değişen ilişki ve kişisel değer barları oluşturur. Bu barlar üzerinden oyuncu hem insanlarla olan bağlarını sürdürmeye hem de ruhsal dengesini korumaya çalışır. Ana Karakter: Mike Mike, büyük şehirde sıradan bir yaşam süren bir ofis çalışanıdır. Yüzeyde her şey yolunda gibi görünse de içten içe çelişkilerle doludur. Günlük yaşamın rutinine sıkışmış, ilişkileri sınanmaya açık bir noktadadır. Evli, çalışıyor, sosyal çevresi var gibi görünüyor ama bir sabah kalktığında bazı seçimlerin ertelenemeyecek kadar yaklaştığını fark eder. Oyuncunun kontrol ettiği Mike, artık hayatına yön veren seçimleri yapmaya başlamak zorundadır. Karakterler ve İlişki Sistemleri Mike’ın hayatındaki dört önemli karakterle olan ilişkisi, oyun boyunca vereceği kararlarla şekillenir. Her bir karakterin Mike ile bir ilişki barı bulunur. Bu barlar 0 ile 100 arasında değişir ve başlangıç noktası olarak her biri 50’den başlar. Bar %0’a düştüğünde, o kişi Mike’ın hayatından çıkar; bu da hikâyenin dramatik kırılma anlarına sebep olur. İlk karakter Lisa’dır. Lisa, Mike’ın eşi. Onunla olan ilişki duygusal bağlılık, sadakat ve empati üzerinden yürür. Mike, Lisa’yla ilgilendiği, onu önemsediği ve dürüst davrandığı sürece ilişki barı yükselir. İhmal, yalan ya da aldatma ise bu ilişkiyi zedeler. İkinci karakter Rebecca’dır. Rebecca, Mike’ın iş yerinden yakın bir arkadaşıdır. Aralarındaki ilişki hem dostça hem de kimi zaman flört etmeye açık sınırda bir gerilim taşır. Rebecca ile olan seçimler Mike’ın sadakati ile arzuları arasında gidip gelmesine sebep olur. Peter, Mike’ın çocukluk arkadaşıdır. Onlarla geçirilen eski günler, nostaljik anılar ve bugünkü bağların ne kadar sağlam kaldığı Peter ile olan ilişkiyi şekillendirir. Samimiyet, sadakat ve geçmişe olan bağlılık bu bağı ayakta tutar. Onu ihmal etmek veya yalan söylemek, yılların dostluğunu bir anda bitirebilir. Son olarak Alex, Mike’ın patronudur. Bu ilişki daha çok disiplin, iş etiği ve kariyerle ilgilidir. İşini iyi yapar, sorumluluklarını yerine getirirse Alex ile olan ilişkisi güçlenir. Ancak işe karşı ilgisizlik veya dürüst olmayan davranışlar Mike’ın işten atılmasına bile sebep olabilir. Kişisel Barlar: İçsel Dengenin Ölçüsü Mike’ın yalnızca sosyal ilişkileri değil, iç dünyası da sürekli bir değişim halindedir. Oyunda dört adet kişisel bar vardır: Mutluluk, Dürüstlük, Şehvet ve İhanet. Her biri 0 ile 100 arasında değişir ve başlangıçta 50 seviyesindedir. Oyuncunun verdiği her karar, bu barlardan bir ya da birkaçını etkiler. Mutluluk barı, Mike’ın yaşam doyumu ve psikolojik dayanıklılığını gösterir. Lisa’yla iyi zamanlar geçirmek, dostlarıyla görüşmek ya da hayırsever davranışlarda bulunmak bu barı yükseltir. İş stresi, tartışmalar ya da ilgisizlik ise mutluluğunu azaltır. Bar sıfırlandığında Mike hayatın anlamını sorgular hale gelir ve “şehir seni mutlu edemedi” diyerek her şeyi bırakıp kendini inzivaya çeker. Dürüstlük barı, Mike’ın doğruluk ve içsel bütünlük derecesini ölçer. Yalan söylemek, gerçekleri gizlemek, manipülasyon bu barı düşürür. Açık sözlü olmak, hataları kabul etmek ve dürüst kalmak ise bu barı yükseltir. Bar sıfıra indiğinde Mike artık aynada kendisini bile tanıyamaz hale gelir ve herkes ondan uzaklaşır. Şehvet barı, Mike’ın tutkularını ve yaşam enerjisini simgeler. Flört, romantizm, fiziksel temas gibi olaylar bu barı yükseltir. Monotonluk, ilgisizlik ya da bastırılmış duygular ise bu barı düşürür. Şehvet barı sıfıra ulaştığında Mike, hayattan zevk alamayan biri olur. İhanet barı, Mike’ın güvensizlik ve sadakatsizlik oranını yansıtır. Aldatma, gizli işler ve ikili oyunlar bu barı artırır. Bar %100’e ulaştığında, Mike’ın çevresindeki herkes onu terk eder. Tüm köprüler yanar ve oyun, dramatik bir yalnızlık sahnesiyle sonlanır. Seçimler ve Etkileri: Her Soru Bir Yol Ayrımı Oyunun kalbinde, her gün Mike’a yöneltilen bir olay ya da soru yer alır. Oyuncuya iki seçenek sunulur. Bu seçenekler hem ilişkileri hem de kişisel barları etkiler. Seçimlerin etkisi bazen hemen görülür, bazen uzun vadede belirginleşir. Örneğin Lisa’nın hazırladığı yemeğe iltifat etmek küçük ama olumlu bir etki yaratırken, Rebecca ile ofiste samimi bir an yaşamak daha karmaşık etkiler doğurabilir. Her karar zincirleme sonuçlara yol açar. Oyunda toplamda en az 50 farklı soru ve olay bulunur. Bunlar Lisa ile tartışmalar, Rebecca ile flört sınırındaki anlar, Peter’la eski defterlerin açılması, Alex’in baskıcı istekleri ya da sokakta karşılaşılan bir evsize verilen tepki gibi geniş bir yelpazeye sahiptir. Sorular yalnızca insanlar üzerinden değil, bazen Mike’ın kişisel iç sesinden de gelir: "Bugün gerçeği söylemeli miyim?", "Bunu hak edecek biri miyim?" gibi. Böylece oyun yalnızca dış dünyaya karşı değil, Mike’ın kendi iç dünyasına karşı da bir mücadele haline gelir. Barlar Sıfırlandığında Ne Olur? Oyun boyunca barların dengeli kalması çok önemlidir. Herhangi bir barın sıfır seviyeye düşmesi, oyunun orada sonlanmasına sebep olur. Ama bu sıradan bir “game over” ekranı değildir. Her barın sıfırlanmasına özel hazırlanmış farklı sonlar vardır. Örneğin mutluluk barı sıfırlandığında, Mike artık bu şehir hayatında anlam bulamaz ve eşyalarını toplayıp hiçbir şey söylemeden uzaklara gider. Dürüstlük barı sıfırlandığında, çevresinde kimse kalmaz, her ilişkisi dağılmıştır ve Mike aynadaki yansımasına bile güvenemez. Şehvet sıfırlandığında hayatı renksizleşir; İhanet %100 olduğunda ise Lisa, Peter ve Rebecca’dan aynı anda veda mesajları alır ve yapayalnız kalır. Çoklu Sonlar: Hangi Mike Olacaksın? Oyun yalnızca tek bir sonla bitmez. Mike’ın ilişkileri ve barlarının birleşimiyle birçok farklı son oluşur. Eğer Lisa ile ilişkisi güçlü, dürüstlük barı yüksek ve ihanet oranı düşükse oyun mutlu bir aile sonuyla biter. Rebecca ile yüksek bir ilişki, şehvet ve ihanetin tavan yaptığı bir durum ise Mike’ın evliliğini bitirip yeni bir aşka yelken açmasına sebep olur. Peter ile yüksek bir dostluk ise geçmişe dönük duygusal bir bağ kurar. Tüm barların ve ilişkilerin düşük olduğu karanlık son ise tam bir yalnızlık ve içsel çöküştür. Oynanış Döngüsü ve Teknik Yapı Oyun portre modunda 2D bir görsel roman tarzında tasarlanır. Günde üç aşamadan oluşur: sabah sahnesi (iç ses veya partnerle), öğlen sahnesi (iş veya sosyal karakterlerle), akşam sahnesi (kararların içselleştirilmesi). Oynanış sırasında hem karakterlerin konuşmaları hem de Mike’ın iç sesi ekranda görünür. Oyuncu seçim yaptıkça barlar güncellenir ve ekranın kenarındaki bar göstergeleri değişir. Oyunun veri yapısı, barları ve karakter ilişkilerini JSON dosyalarında saklar. Manuel ve otomatik kayıt sistemiyle oyuncu istediği yerden devam edebilir. Mike’ın Yolu — Detaylı Oyun Tasarımı ve Hikâye Anlatımı Oyun Dünyası ve Teması “Mike’ın Yolu”, büyük şehirde yaşayan sıradan bir adamın, Mike’ın hayatındaki kararlarla şekillenen bir yolculuğudur. Oyun, oyuncuya Mike’ın iç dünyasındaki çatışmaları ve çevresiyle olan ilişkilerini çok katmanlı bir şekilde deneyimletir. Hikaye, sıradan hayatın içinde sıkışan bir adamın seçimleri üzerinden ilerler; bu seçimler bazen çok küçük, bazen hayatı tamamen değiştirecek kadar büyük olur. Oyuncunun her seçimi, Mike’ın ilişki barlarını ve kişisel değerlerini değiştirir, farklı sonuçlar doğurur. Karakterler ve Kişilikleri Mike: Ana karakterimiz, 30’larında, sıradan bir ofis çalışanı. Evli, sosyal ama zaman zaman hayattan bezmiş biri. İçsel çatışmaları ve bastırdığı duyguları var. Lisa: Mike’ın eşi. Evine ve Mike’a bağlı, ama aynı zamanda onun davranışlarına karşı hassas. Dürüstlük ve sadakat onun için çok önemli. Rebecca: İş yerinden yakın bir arkadaş. Samimi, zeki ama flörtöz. Mike’ın hayatına çekici ama riskli bir unsur olarak giriyor. Peter: Çocukluk arkadaşı. Sadık, espri yeteneği yüksek ve geçmişten gelen bağları çok kuvvetli. Alex: Mike’ın patronu. Sert, disiplinli ve iş odaklı. Mike’ın kariyerini yakından takip ediyor. Barlar ve Etkileri Lisa İlişki Barı (Başlangıç: 50) Rebecca İlişki Barı (Başlangıç: 50) Peter İlişki Barı (Başlangıç: 50) Alex İlişki Barı (Başlangıç: 50) Mutluluk Barı (Başlangıç: 50) Dürüstlük Barı (Başlangıç: 50) Şehvet Barı (Başlangıç: 50) İhanet Barı (Başlangıç: 50) Oyun Mekaniği Oyuncuya gün içinde farklı zamanlarda toplam 50 karar sorulur. Her karar için iki seçenek vardır. Seçilen seçenekler hem belirli karakterlerin ilişki barlarını hem de kişisel barları etkiler. Bazı seçenekler birden fazla barı değiştirir. Örneğin Lisa ile yapılan bir konuşmada dürüstlük barı artarken, şehvet barı düşebilir. Ya da Rebecca ile samimi bir an, ihanet barını yükseltebilir. Her bar sıfıra indiğinde oyun o anda özel olarak yazılmış bir sonla biter. 50 Örnek Karar ve Seçenekler 1. Sabah Lisa kahvaltı hazırlamış, Mike ona ne der? A) “Çok güzel olmuş, teşekkür ederim.” Lisa barı +5, Mutluluk +3 B) “Yine mi aynı şey, biraz değişiklik yap.” Lisa barı -7, Mutluluk -2 2. İşe giderken Rebecca mesaj attı, ne yanıt verirsin? A) “Günaydın, öğle arasında buluşalım mı?” Rebecca barı +5, Şehvet +4, İhanet +3 B) “Şu an yoğunum, sonra konuşuruz.” Rebecca barı -3, Dürüstlük +2 3. Patron Alex, seni sert bir şekilde eleştirdi. Nasıl tepki verirsin? A) “Haklısınız, daha dikkatli olacağım.” Alex barı +5, Dürüstlük +4, Mutluluk -2 B) “Bana fazla yükleniyorsunuz, adil değil.” Alex barı -7, Mutluluk -3 4. Peter’la eski günlerden bahsederken o zor durumda olduğunu söylüyor. Ne yaparsın? A) “Yanındayım, neye ihtiyacın varsa söyle.” Peter barı +6, Mutluluk +3 B) “Kendi işimle meşgulüm, üzgünüm.” Peter barı -5, Mutluluk -2 5. Lisa seninle dürüstçe konuşmak istiyor, ne yaparsın? A) “Tabii, ne söylemek istiyorsan dinliyorum.” Lisa barı +7, Dürüstlük +6 B) “Bunları konuşmak istemiyorum.” Lisa barı -8, Dürüstlük -5 6. İş çıkışı Rebecca ile bir kafede buluşuyorsun, yanında Lisa varken mesaj atıyor, ne yaparsın? A) “Lisa burada, sonra konuşalım.” Rebecca barı -3, Dürüstlük +3 B) “Hemen sana geliyorum.” Rebecca barı +6, Lisa barı -10, İhanet +7 7. Yorgunluktan evde erken yatmak istiyorsun, Lisa ısrarla dışarı çıkmayı teklif ediyor. A) “Bugün yorgunum, evde kalalım.” Lisa barı -4, Mutluluk -3 B) “Tamam, seninle dışarı çıkalım.” Lisa barı +5, Mutluluk +4 8. Alex önemli bir projeyi sana teslim etti, zamanında yetiştiremeyebilirsin. A) “Gerçekçi zaman verirsek başarı şansı artar.” Alex barı +4, Dürüstlük +5 B) “Mümkün olduğunca hızlı yapacağım, sorun yok.” Alex barı -2, Mutluluk +1 9. Peter, geçmişte yaptığın bir hatayı hatırlatıyor. A) “Haklısın, özür dilerim.” Peter barı +4, Dürüstlük +6 B) “O günler geçti, unutalım.” Peter barı -5 10. Lisa, bir sır sakladığını düşünüyor. A) “Sana her şeyi anlatacağım.” Lisa barı +8, Dürüstlük +7 B) “Beni yanlış anlıyorsun.” Lisa barı -10, Dürüstlük -8 ...Ve bu şekilde 50 soruya kadar devam eder. Her biri farklı barları etkiler. Bazı örnekler arasında Mike’ın kişisel iç sesinden gelen sorular, iş ortamındaki zorluklar, çocukluk anıları, romantik ve ahlaki ikilemler yer alır. Örnek Diyaloglardan Kesitler Lisa: “Mike, seninle daha fazla zaman geçiremediğimiz için çok üzgünüm. Bana gerçekten ihtiyacın var mı?” Mike: “Biliyorum, Lisa. İş çok yoğun ama seni seviyorum. Sadece biraz nefes almaya ihtiyacım var.” Rebecca: “Biliyorum Mike, aramızda başka bir şey olabilir. Ama bu tehlikeli... Ne düşünüyorsun?” Mike: “Rebecca, bu işi kendi haline bırakmalıyız. Lisa’ya ihanet etmek istemiyorum.” Peter: “Yıllar geçti ama sen hala aynı adamsın. Dürüstlüğünle dostluğumuz ayakta kaldı, onu kaybetmek istemem.” Alex: “Mike, bu işten beklentim yüksek. Seni seçtim çünkü yeteneklisin. Ama sınırlarını zorlaman gerekiyor.” Barların Sıfırlanması ve Sonlar Barlar 0’a düştüğünde, oyun aşağıdaki özel sonlardan biriyle biter: Mutluluk Barı 0: “Şehir hayatı seni mutlu edemedi. Her şeyi bıraktın, uzaklarda sessiz bir hayat sürüyorsun.” (Mike yalnızlık ve inziva yolunu seçer.) Dürüstlük Barı 0: “Kendi yalanların seni yuttu. Artık kendine bile güvenemiyorsun, çevrendekiler senden uzaklaştı.” Şehvet Barı 0: “Tutkularını yitirdin, hayatın renksizleşti. Artık hiçbir şey sana zevk vermiyor.” İhanet Barı 100: “Tüm hayatını yalanlar üzerine kurdun. Lisa, Peter ve Rebecca seni terk etti, yalnız kaldın.” Lisa Barı 0: “Evliliğin sona erdi. Lisa hayatından çıktı, ev yalnızlaştı.” Rebecca Barı 0: “Rebecca ile bağın koptu. İş yerindeki o gizemli dostluğun bitti.” Peter Barı 0: “Çocukluk dostun seni hayatından çıkardı. Geçmişe dair ne varsa yitirildi.” Alex Barı 0: “Patronun sabrını kaybetti. İşini kaybettin, belirsiz bir geleceğe doğru...” Oyun Atmosferi ve Görsel Tasarım Oyun, sade ama duygusal bir 2D görsel roman tarzında tasarlanacak. Karakter portreleri duygularını yansıtacak şekilde animasyonlu olacak. Arka planlar gündelik şehir yaşamını, ev ortamını ve ofis ortamını gerçekçi bir şekilde yansıtacak. Atmosferin ruhuna uygun hafif bir caz ve elektronik müzik alt yapısı oyuncunun deneyimini derinleştirecek. Ekranın kenarlarında barlar canlı renklerle gösterilecek, bu da oyuncuya sürekli geri bildirim verecek. Özet “Mike’ın Yolu”, basit görünen ama çok katmanlı ve duygu yüklü bir oyun. Oyuncuyu karakterlerle bağ kurmaya, seçimlerin sonuçlarını içselleştirmeye ve hayattaki ahlaki ikilemleri derinlemesine deneyimlemeye çağırıyor. Mike’ın seçimleri, sadece ilişkilerini değil, kendi ruh sağlığını ve yaşam yolunu belirliyor. Her seçim, yeni bir olasılığa kapı açıyor, ama her yanlış adım da bir sonuca götürüyor. Bu yüzden oyuncunun stratejik ve duygusal zekasını kullanması gerekiyor.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // OptionButton: For displaying a choice var OptionButton = Container.expand(function () { var self = Container.call(this); self.bg = self.attachAsset('option_btn', { anchorX: 0.5, anchorY: 0.5 }); self.text = null; self.callback = null; self.setText = function (str) { if (self.text) self.removeChild(self.text); self.text = new Text2(str, { size: 54, fill: '#222222' }); self.text.anchor.set(0.5, 0.5); self.text.x = 0; self.text.y = 0; self.addChild(self.text); }; self.setCallback = function (cb) { self.callback = cb; }; self.down = function (x, y, obj) { if (self.callback) self.callback(); }; return self; }); // Passive background object base class var PassiveBgObject = Container.expand(function () { var self = Container.call(this); self.speed = 0; self.assetId = ''; self.asset = null; self.setAsset = function (assetId) { if (self.asset) self.removeChild(self.asset); self.assetId = assetId; self.asset = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); }; self.resetPosition = function () { // Start just outside right edge, random Y self.x = 2048 + (self.asset ? self.asset.width : 100) / 2 + Math.random() * 200; self.y = 200 + Math.random() * 2100; }; self.update = function () { if (typeof self.lastX === "undefined") self.lastX = self.x; self.x -= self.speed; // If off screen to the left, reset if (self.lastX >= -200 && self.x < -200) { self.resetPosition(); } self.lastX = self.x; }; return self; }); // Motorcycle var BgMotorcycle = PassiveBgObject.expand(function () { var self = PassiveBgObject.call(this); self.setAsset('bg_motorcycle'); self.speed = 4.0 + Math.random() * 1.5; self.resetPosition(); return self; }); // Heart var BgHeart = PassiveBgObject.expand(function () { var self = PassiveBgObject.call(this); self.setAsset('bg_heart'); self.speed = 2.7 + Math.random() * 1.2; self.resetPosition(); return self; }); // Football var BgFootball = PassiveBgObject.expand(function () { var self = PassiveBgObject.call(this); self.setAsset('bg_football'); self.speed = 2.5 + Math.random() * 1.2; self.resetPosition(); return self; }); // Car var BgCar = PassiveBgObject.expand(function () { var self = PassiveBgObject.call(this); self.setAsset('bg_car'); self.speed = 3.2 + Math.random() * 1.5; self.resetPosition(); return self; }); // Briefcase var BgBriefcase = PassiveBgObject.expand(function () { var self = PassiveBgObject.call(this); self.setAsset('bg_briefcase'); self.speed = 2.2 + Math.random() * 1.2; self.resetPosition(); return self; }); // RelationshipBar: For displaying and updating a bar (happiness, honesty, lust, betrayal) var RelationshipBar = Container.expand(function () { var self = Container.call(this); self.bg = self.attachAsset('bar_bg', { anchorX: 0, anchorY: 0 }); self.fill = null; self.label = null; self.value = 100; // 0-100 self.maxWidth = 400; self.type = 'happy'; // 'happy', 'honest', 'lust', 'betray' self.setType = function (type) { self.type = type; var fillId = 'bar_fill_happy'; if (type === 'honest') fillId = 'bar_fill_honest'; if (type === 'lust') fillId = 'bar_fill_lust'; if (type === 'betray') fillId = 'bar_fill_betray'; if (self.fill) self.removeChild(self.fill); self.fill = self.attachAsset(fillId, { anchorX: 0, anchorY: 0 }); self.fill.x = 0; self.fill.y = 0; self.fill.width = self.maxWidth; self.fill.height = 40; self.fill.zIndex = 1; self.bg.zIndex = 0; self.setValue(self.value); }; self.setValue = function (val) { self.value = Math.max(0, Math.min(100, val)); if (self.fill) { self.fill.width = self.maxWidth * (self.value / 100); } if (self.label) { self.label.setText(self.value + '%'); } }; self.setLabel = function (text) { if (self.label) self.removeChild(self.label); self.label = new Text2(text, { size: 36, fill: '#ffffff' }); self.label.anchor.set(1, 0.5); self.label.x = self.maxWidth + 20; self.label.y = 20; self.addChild(self.label); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181818 }); /**** * Game Code ****/ // Animate passive background objects // Sağdan sola giden araba // Sağdan sola giden iş çantası // Sağdan sola giden ateşli kalp // Sağdan sola giden futbol topu // Sağdan sola giden motor // --- Shop/Store assets (right side) --- // Example id, replace with real if (typeof bgObjects !== "undefined") { for (var i = 0; i < bgObjects.length; i++) { if (bgObjects[i] && typeof bgObjects[i].update === "function") { bgObjects[i].update(); } } } // No per-frame logic needed // Not: 'background' asseti image olarak tanımlanmalı, ör: LK.init.image('background', {width:2048, height:2732, id:'YOUR_IMAGE_ID'}) var backgroundNode = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); backgroundNode.width = 2048; backgroundNode.height = 2732; backgroundNode.x = 0; backgroundNode.y = 0; backgroundNode.zIndex = -100; // Her şeyin arkasında dursun game.addChild(backgroundNode); // --- Passive background objects (car, briefcase, heart, football, motorcycle) --- var bgObjects = []; function spawnBgObjects() { // Remove old ones if any for (var i = 0; i < bgObjects.length; i++) { if (bgObjects[i] && bgObjects[i].parent) { game.removeChild(bgObjects[i]); } } bgObjects = []; // Add 2 of each for variety for (var i = 0; i < 2; i++) { var car = new BgCar(); var briefcase = new BgBriefcase(); var heart = new BgHeart(); var football = new BgFootball(); var motorcycle = new BgMotorcycle(); game.addChild(car); game.addChild(briefcase); game.addChild(heart); game.addChild(football); game.addChild(motorcycle); bgObjects.push(car, briefcase, heart, football, motorcycle); } } spawnBgObjects(); // Çarpıcı seçimler: her 4-6 sahnede bir, yüksek risk/ödül, animasyonlu, barları büyük oranda etkiler // --- Dramatic Choice (Çarpıcı Seçim) System --- var dramaticChoices = [{ id: "rebecca_room", text: "Rebecca ile iş gezisindesiniz. Aynı odada mı kalacaksınız, farklı mı?", portrait: "rebecca", speaker: "Rebecca", dramatic: true, options: [{ text: "Aynı odada kal", effects: { rebecca: 15, lust: 15, betray: 15 }, meta: { memoryLabel: "rebecca_room_same" } }, { text: "Farklı odada kal", effects: { honest: 10, rebecca: -5 }, meta: { memoryLabel: "rebecca_room_diff" } }] }, { id: "lisa_warns_alex", text: "Lisa seni, iş yerinde Alex ile fazla yakın görünmen konusunda uyarıyor. Tepkin ne olur?", portrait: "lisa", speaker: "Lisa", dramatic: true, options: [{ text: "Anlar ve saygı gösterirsin", effects: { lisa: 20, honest: 15 }, meta: { memoryLabel: "lisa_warns_respect" } }, { text: "Umursamaz davranırsın", effects: { lisa: -20, betray: 15 }, meta: { memoryLabel: "lisa_warns_ignore" } }] }, { id: "alex_secret", text: "Alex senden gizli bir bilgi istiyor. Paylaşacak mısın?", portrait: "alex", speaker: "Alex", dramatic: true, options: [{ text: "Paylaş", effects: { betray: 20, alex: 10 }, meta: { memoryLabel: "alex_secret_share" } }, { text: "Sakla", effects: { honest: 20, alex: -10 }, meta: { memoryLabel: "alex_secret_hide" } }] }, { id: "peter_lisa_fears", text: "Peter sana, Lisa ile ilgili endişelerini paylaşıyor. Ona inanacak mısın?", portrait: "peter", speaker: "Peter", dramatic: true, options: [{ text: "Evet", effects: { peter: 15, honest: 10 }, meta: { memoryLabel: "peter_lisa_believe" } }, { text: "Hayır", effects: { peter: -15, betray: 10 }, meta: { memoryLabel: "peter_lisa_deny" } }] }, { id: "rebecca_night", text: "Rebecca gece seni evine davet ediyor. Gidiyor musun?", portrait: "rebecca", speaker: "Rebecca", dramatic: true, options: [{ text: "Evet", effects: { rebecca: 20, lust: 15, betray: 20 }, meta: { memoryLabel: "rebecca_night_yes" } }, { text: "Hayır", effects: { honest: 15 }, meta: { memoryLabel: "rebecca_night_no" } }] }, { id: "lisa_serious_talk", text: "Lisa, seninle ciddi bir konuşma yapmak istiyor. Onu dinleyecek misin?", portrait: "lisa", speaker: "Lisa", dramatic: true, options: [{ text: "Dinle", effects: { lisa: 20, honest: 10 }, meta: { memoryLabel: "lisa_serious_listen" } }, { text: "Dinleme", effects: { lisa: -20, happy: -15 }, meta: { memoryLabel: "lisa_serious_ignore" } }] }, { id: "alex_secret_deal", text: "Alex ile gizli bir anlaşma teklif ediyor. Kabul edecek misin?", portrait: "alex", speaker: "Alex", dramatic: true, options: [{ text: "Evet", effects: { alex: 20, betray: 20 }, meta: { memoryLabel: "alex_deal_yes" } }, { text: "Hayır", effects: { honest: 20, alex: -15 }, meta: { memoryLabel: "alex_deal_no" } }] }, { id: "peter_big_secret", text: "Peter, seni büyük bir sırrı hakkında uyarıyor. Güveniyor musun?", portrait: "peter", speaker: "Peter", dramatic: true, options: [{ text: "Evet", effects: { peter: 20, honest: 10 }, meta: { memoryLabel: "peter_secret_trust" } }, { text: "Hayır", effects: { peter: -20, betray: 15 }, meta: { memoryLabel: "peter_secret_distrust" } }] }, { id: "rebecca_club", text: "Rebecca ile bir gece kulübünde dans ediyorsun. Daha yakın davranacak mısın?", portrait: "rebecca", speaker: "Rebecca", dramatic: true, options: [{ text: "Evet", effects: { rebecca: 15, lust: 15, betray: 10 }, meta: { memoryLabel: "rebecca_club_yes" } }, { text: "Hayır", effects: { honest: 10 }, meta: { memoryLabel: "rebecca_club_no" } }] }, { id: "lisa_gossip", text: "Lisa seni iş arkadaşlarınla ilgili dedikodulara karışmakla suçluyor. Savunacak mısın?", portrait: "lisa", speaker: "Lisa", dramatic: true, options: [{ text: "Savun", effects: { lisa: 10, honest: 15 }, meta: { memoryLabel: "lisa_gossip_defend" } }, { text: "Kabullen", effects: { lisa: -15, betray: 10 }, meta: { memoryLabel: "lisa_gossip_admit" } }] }, { id: "alex_promotion", text: "Alex, seni iş yerinde terfi ile ödüllendiriyor ama bir karşılık bekliyor. Kabul edecek misin?", portrait: "alex", speaker: "Alex", dramatic: true, options: [{ text: "Evet", effects: { alex: 25, betray: 25 }, meta: { memoryLabel: "alex_promotion_yes" } }, { text: "Hayır", effects: { honest: 20 }, meta: { memoryLabel: "alex_promotion_no" } }] }, { id: "peter_sacrifice", text: "Peter’in sana yardım etmek için büyük bir fedakarlık yapması gerekiyor. Kabul edecek misin?", portrait: "peter", speaker: "Peter", dramatic: true, options: [{ text: "Evet", effects: { peter: 25, happy: 15 }, meta: { memoryLabel: "peter_sacrifice_yes" } }, { text: "Hayır", effects: { peter: -20, betray: 10 }, meta: { memoryLabel: "peter_sacrifice_no" } }] }, { id: "rebecca_restaurant", text: "Rebecca, iş seyahatinde seni bir restoranda yalnız bırakıyor. Tek başına kalacak mısın yoksa kalabalığa mı karışacaksın?", portrait: "rebecca", speaker: "Rebecca", dramatic: true, options: [{ text: "Tek başına", effects: { rebecca: 10, lust: 10 }, meta: { memoryLabel: "rebecca_restaurant_alone" } }, { text: "Kalabalık", effects: { honest: 10 }, meta: { memoryLabel: "rebecca_restaurant_crowd" } }] }, { id: "lisa_memory", text: "Lisa sana eski bir anısını anlatıyor ve senden destek bekliyor. Onun yanında olacak mısın?", portrait: "lisa", speaker: "Lisa", dramatic: true, options: [{ text: "Evet", effects: { lisa: 20, happy: 15 }, meta: { memoryLabel: "lisa_memory_yes" } }, { text: "Hayır", effects: { lisa: -15 }, meta: { memoryLabel: "lisa_memory_no" } }] }, { id: "alex_ethics", text: "Alex’in zorlayıcı teklifine karşılık verirken etik dışı bir şey yapman isteniyor. Kabul mü?", portrait: "alex", speaker: "Alex", dramatic: true, options: [{ text: "Evet", effects: { alex: 20, betray: 25 }, meta: { memoryLabel: "alex_ethics_yes" } }, { text: "Hayır", effects: { honest: 20 }, meta: { memoryLabel: "alex_ethics_no" } }] }, { id: "peter_secret_share", text: "Peter seni beklenmedik bir şekilde büyük bir sırrını açıklıyor. Tepkin ne olur?", portrait: "peter", speaker: "Peter", dramatic: true, options: [{ text: "Sırlarınızı paylaşmaya devam edersin", effects: { peter: 20, honest: 15 }, meta: { memoryLabel: "peter_secret_share_yes" } }, { text: "Mesafeli olursun", effects: { peter: -15, betray: 10 }, meta: { memoryLabel: "peter_secret_share_no" } }] }, { id: "rebecca_bar_lisa", text: "Rebecca ile iş sonrası bara gittiniz. Lisa ile yüzleşmeye hazır mısın?", portrait: "rebecca", speaker: "Rebecca", dramatic: true, options: [{ text: "Evet", effects: { betray: 20, lust: 15, rebecca: 10 }, meta: { memoryLabel: "rebecca_bar_lisa_yes" } }, { text: "Hayır", effects: { honest: 15, lisa: 10 }, meta: { memoryLabel: "rebecca_bar_lisa_no" } }] }, { id: "lisa_crisis", text: "Lisa sana, evlilikte bir kriz yaşıyor ve profesyonel yardım almak istiyor. Destek verir misin?", portrait: "lisa", speaker: "Lisa", dramatic: true, options: [{ text: "Evet", effects: { lisa: 25, happy: 20 }, meta: { memoryLabel: "lisa_crisis_yes" } }, { text: "Hayır", effects: { lisa: -25 }, meta: { memoryLabel: "lisa_crisis_no" } }] }, { id: "alex_risk", text: "Alex, kariyerin için büyük bir tehlike barındıran bir riski göze almana izin veriyor. Kabul mü?", portrait: "alex", speaker: "Alex", dramatic: true, options: [{ text: "Evet", effects: { alex: 30, betray: 30 }, meta: { memoryLabel: "alex_risk_yes" } }, { text: "Hayır", effects: { honest: 20 }, meta: { memoryLabel: "alex_risk_no" } }] }, { id: "peter_conflict", text: "Peter ile aranızda aniden büyük bir anlaşmazlık çıkıyor. Özür dileyecek misin?", portrait: "peter", speaker: "Peter", dramatic: true, options: [{ text: "Evet", effects: { peter: 20, happy: 15 }, meta: { memoryLabel: "peter_conflict_yes" } }, { text: "Hayır", effects: { peter: -20, betray: 15 }, meta: { memoryLabel: "peter_conflict_no" } }] }]; // Dramatic choice frequency: every 4-6 turns, randomize var nextDramaticTurn = 4 + Math.floor(Math.random() * 3); var dramaticHistory = []; // Helper: get a random dramatic choice not recently shown function getDramaticChoice() { var available = []; for (var i = 0; i < dramaticChoices.length; i++) { if (dramaticHistory.indexOf(dramaticChoices[i].id) === -1) { available.push(dramaticChoices[i]); } } // If all have been shown, reset history if (available.length === 0) { dramaticHistory = []; available = dramaticChoices.slice(); } var idx = Math.floor(Math.random() * available.length); return available[idx]; } // Show a dramatic choice with animation, music pause, and shadow overlay function showDramaticChoice() { // Remove old option buttons for (var i = 0; i < optionButtons.length; i++) { game.removeChild(optionButtons[i]); } optionButtons = []; // Pick a dramatic choice var node = getDramaticChoice(); dramaticHistory.push(node.id); // Pause music (if any) if (typeof LK.stopMusic === "function") LK.stopMusic(); // Shadow overlay if (!game._dramaticShadow) { var shadow = LK.getAsset('bar_bg', { anchorX: 0, anchorY: 0 }); shadow.width = 2048; shadow.height = 2732; shadow.x = 0; shadow.y = 0; shadow.alpha = 0.0; // Start fully transparent shadow.zIndex = 99; game.addChild(shadow); game._dramaticShadow = shadow; // Animate shadow fade-in tween(shadow, { alpha: 0.7 }, { duration: 220, easing: tween.easeOut }); } else { // If already present, ensure it's visible and interactive game._dramaticShadow.alpha = 0.7; game._dramaticShadow.zIndex = 99; } // Portrait if (portraitNode && node.portrait && LK.getAsset(node.portrait, {})) { portraitNode.texture = LK.getAsset(node.portrait, {}).texture; portraitNode.tint = 0xffffff; } // Speaker if (speakerText) speakerText.setText(node.speaker ? node.speaker : ''); // Story text if (storyText) { storyText.setText(node.text); storyText.alpha = 1.0; // No animation } // Dramatic option buttons: ensure visible, enabled, and selectable for (var i = 0; i < node.options.length; i++) { (function (opt, idx) { var btn = new OptionButton(); btn.setText(opt.text); // Büyük ve dikkat çekici: butonları daha büyük yap btn.scale.x = 1.35; btn.scale.y = 1.35; // Ekranda tamamen görünür ve aralıklı olacak şekilde ayarla // Yüksekliğe göre ortala, iki seçenek için yukarıdan ve aşağıdan eşit boşluk bırak var totalBtnHeight = 2 * (btn.bg.height * btn.scale.y) + 120; var startY = 1800 - totalBtnHeight / 2; btn.x = 2048 / 2; btn.y = startY + idx * (btn.bg.height * btn.scale.y + 120); btn.alpha = 1.0; btn.bg.tint = 0x000000; if (btn.text && btn.text.style) btn.text.style.fill = '#ffffff'; btn.zIndex = 100; btn.interactive = true; btn.buttonMode = true; // Make sure button is enabled and not grayed out btn.bg.tint = 0x000000; if (btn.text && btn.text.style) btn.text.style.fill = '#ffffff'; // Remove any previous disabled state btn.alpha = 1.0; btn.visible = true; btn.setCallback(function () { // Seçim sırasında iki butonu da büyüt ve animasyon ekle for (var j = 0; j < optionButtons.length; j++) { var b = optionButtons[j]; // Seçilen buton daha fazla büyüsün, diğeri de büyüsün ama biraz az var targetScale = b === btn ? 1.55 : 1.25; tween(b.scale, { x: targetScale, y: targetScale }, { duration: 220, easing: tween.easeOut }); tween(b, { alpha: 1 }, { duration: 220, easing: tween.easeOut }); } // Seçimden kısa süre sonra butonları ve gölgeyi kaldır LK.setTimeout(function () { // Remove shadow overlay with fade out if (game._dramaticShadow) { tween(game._dramaticShadow, { alpha: 0 }, { duration: 180, easing: tween.easeIn, onFinish: function onFinish() { if (game._dramaticShadow) { game.removeChild(game._dramaticShadow); game._dramaticShadow = null; } } }); } // Remove buttons instantly for (var j = 0; j < optionButtons.length; j++) { (function (b) { game.removeChild(b); })(optionButtons[j]); } optionButtons = []; // Apply effects (dramatic: +10~+30 or -30) applyDramaticEffects(opt.effects, opt.meta); // Resume music (if any) if (typeof LK.playMusic === "function") LK.playMusic('musicId'); // Next dramatic turn: 4-6 turns later nextDramaticTurn = turnCount + 4 + Math.floor(Math.random() * 3); // Continue with normal story LK.setTimeout(function () { var nextIdx = getNextNode(); currentNode = nextIdx; showStoryNode(currentNode); }, 600); }, 260); }); game.addChild(btn); optionButtons.push(btn); })(node.options[i], i); } } // Apply dramatic effects: bar changes are much larger function applyDramaticEffects(effects, meta) { if (!effects) return; // Record memory if (meta && meta.memoryLabel) pastChoices.push(meta.memoryLabel); // Dramatic: apply full effect value (not just +1/-1) if (typeof effects.lisa === 'number') rel_lisa = Math.max(0, Math.min(100, rel_lisa + effects.lisa)); if (typeof effects.rebecca === 'number') rel_rebecca = Math.max(0, Math.min(100, rel_rebecca + effects.rebecca)); if (typeof effects.peter === 'number') rel_peter = Math.max(0, Math.min(100, rel_peter + effects.peter)); if (typeof effects.alex === 'number') rel_alex = Math.max(0, Math.min(100, rel_alex + effects.alex)); if (typeof effects.happy === 'number') bar_happy = Math.max(0, Math.min(100, bar_happy + effects.happy)); if (typeof effects.honest === 'number') bar_honest = Math.max(0, Math.min(100, bar_honest + effects.honest)); if (typeof effects.lust === 'number') bar_lust = Math.max(0, Math.min(100, bar_lust + effects.lust)); if (typeof effects.betray === 'number') bar_betray = Math.max(0, Math.min(100, bar_betray + effects.betray)); // Shadow bar: dramatic choices have bigger impact if (typeof effects.betray === 'number' && effects.betray > 0) bar_shadow = Math.max(0, Math.min(100, bar_shadow + 10)); if (typeof effects.honest === 'number' && effects.honest > 0) bar_shadow = Math.max(0, bar_shadow - 5); updateBars(); turnCount++; // Cross effects applyCrossEffects(effects, meta); // Check for ending if (bar_happy <= 0) { showEnding('Mutluluk sıfırlandı. Mike depresyona girdi.'); return; } if (bar_honest <= 0) { showEnding('Dürüstlük sıfırlandı. Mike yalanlarla dolu bir hayata saplandı.'); return; } if (bar_lust <= 0) { showEnding('Şehvet sıfırlandı. Mike hayattan keyif alamıyor.'); return; } if (bar_betray >= 100) { showEnding('İhanet %100 oldu. Mike ilişkilerini kaybetti.'); return; } } // Each story node: { text, options: [ {text, effects, next} ], portrait, speaker } // --- Story Data --- // Character portraits (simple colored boxes for now) // Bar backgrounds and fills // Option buttons // --- Whiskey'e özel sorular (yalnızca satın alındıysa gösterilecek) --- var whiskeyQuestions = [{ id: "whiskey_intro", text: "Whiskey: 'Hav hav! Mike, parka gidelim mi?'", portrait: "whiskey", speaker: "Whiskey", options: [{ text: "Whiskey'i parka götür.", effects: { happy: 5 } }, { text: "Bugün evde kalalım.", effects: { happy: -2 } }] }, { id: "whiskey_walk", text: "Whiskey kapının önünde heyecanla bekliyor. Dışarı çıkarmak ister misin?", portrait: "whiskey", speaker: "Whiskey", options: [{ text: "Whiskey ile uzun yürüyüş yap.", effects: { happy: 5 } }, { text: "Kısa bir yürüyüş yap.", effects: { happy: 2 } }, { text: "Yürüyüşe çıkma.", effects: { happy: -3 } }] }, { id: "whiskey_vet", text: "Whiskey biraz halsiz görünüyor. Veterinere götürecek misin?", portrait: "whiskey", speaker: "Whiskey", options: [{ text: "Veterinere götür. ($200 harca)", effects: { happy: 5 }, meta: { type: "whiskey_spend", money: -200 } }, { text: "Evde dinlensin.", effects: { happy: -2 } }] }, { id: "whiskey_toy", text: "Whiskey yeni bir oyuncak istiyor.", portrait: "whiskey", speaker: "Whiskey", options: [{ text: "Oyuncak al. ($50 harca)", effects: { happy: 3 }, meta: { type: "whiskey_spend", money: -50 } }, { text: "Oyuncak alma.", effects: { happy: -2 } }] }, { id: "whiskey_bath", text: "Whiskey çamura bulandı! Yıkayacak mısın?", portrait: "whiskey", speaker: "Whiskey", options: [{ text: "Whiskey'i yıka.", effects: { happy: 2 } }, { text: "Yıkamadan bırak.", effects: { happy: -3 } }] }, { id: "whiskey_trick", text: "Whiskey yeni bir numara öğrenmek istiyor. Öğretecek misin?", portrait: "whiskey", speaker: "Whiskey", options: [{ text: "Yeni numara öğret.", effects: { happy: 4 } }, { text: "Vakit ayırma.", effects: { happy: -2 } }] }, { id: "whiskey_vacation", text: "Tatile çıkacaksınız. Whiskey'i de götürecek misin?", portrait: "whiskey", speaker: "Whiskey", options: [{ text: "Whiskey'i de götür. ($300 harca)", effects: { happy: 5 }, meta: { type: "whiskey_spend", money: -300 } }, { text: "Whiskey'i pansiyona bırak. ($150 harca)", effects: { happy: 2 }, meta: { type: "whiskey_spend", money: -150 } }] }, { id: "whiskey_birthday", text: "Whiskey'in doğum günü! Ona özel bir şey yapmak ister misin?", portrait: "whiskey", speaker: "Whiskey", options: [{ text: "Köpek pastası al. ($80 harca)", effects: { happy: 4 }, meta: { type: "whiskey_spend", money: -80 } }, { text: "Sadece sarıl.", effects: { happy: 2 } }] }, { id: "whiskey_lost", text: "Whiskey bahçede kayboldu! Arayacak mısın?", portrait: "whiskey", speaker: "Whiskey", options: [{ text: "Bahçede ara.", effects: { happy: 3 } }, { text: "Kendi gelir diye bekle.", effects: { happy: -3 } }] }, { id: "whiskey_vet2", text: "Whiskey aşı zamanı geldi. Aşı yaptıracak mısın?", portrait: "whiskey", speaker: "Whiskey", options: [{ text: "Aşı yaptır. ($120 harca)", effects: { happy: 3 }, meta: { type: "whiskey_spend", money: -120 } }, { text: "Aşıyı ertele.", effects: { happy: -2 } }] }]; // --- Villa'ya davet eventleri ve özel sorular (her karakter için 2'şer tane) --- var villaInviteEvents = [{ id: "villa_invite_lisa", text: "Artık bir villan var! Lisa'yı eve davet etmek ister misin?", portrait: "lisa", speaker: "Lisa", options: [{ text: "Lisa'yı villaya davet et.", effects: { lisa: 15, happy: 5 }, meta: { type: "villa_invite", character: "lisa" } }, { text: "Davet etme.", effects: { lisa: -2 } }] }, { id: "villa_invite_rebecca", text: "Artık bir villan var! Rebecca'yı eve davet etmek ister misin?", portrait: "rebecca", speaker: "Rebecca", options: [{ text: "Rebecca'yı villaya davet et.", effects: { rebecca: 15, happy: 5 }, meta: { type: "villa_invite", character: "rebecca" } }, { text: "Davet etme.", effects: { rebecca: -2 } }] }, { id: "villa_invite_peter", text: "Artık bir villan var! Peter'ı eve davet etmek ister misin?", portrait: "peter", speaker: "Peter", options: [{ text: "Peter'ı villaya davet et.", effects: { peter: 15, happy: 5 }, meta: { type: "villa_invite", character: "peter" } }, { text: "Davet etme.", effects: { peter: -2 } }] }, { id: "villa_invite_alex", text: "Artık bir villan var! Alex'i eve davet etmek ister misin?", portrait: "alex", speaker: "Alex", options: [{ text: "Alex'i villaya davet et.", effects: { alex: 15, happy: 5 }, meta: { type: "villa_invite", character: "alex" } }, { text: "Davet etme.", effects: { alex: -2 } }] }]; var villaSpecialQuestions = [ // Lisa { id: "villa_lisa_1", text: "Lisa: 'Bu evde birlikte yeni anılar biriktirelim mi?'", portrait: "lisa", speaker: "Lisa", options: [{ text: "Evet, birlikte çok güzel anılarımız olacak.", effects: { lisa: 10, happy: 5 } }, { text: "Ev güzel ama önemli olan sensin.", effects: { lisa: 7, honest: 3 } }] }, { id: "villa_lisa_2", text: "Lisa: 'Villada bir parti verelim mi?'", portrait: "lisa", speaker: "Lisa", options: [{ text: "Harika fikir, parti verelim.", effects: { lisa: 8, happy: 4 } }, { text: "Parti istemiyorum.", effects: { lisa: -3 } }] }, // Rebecca { id: "villa_rebecca_1", text: "Rebecca: 'Villanın havuzunda gece yüzmek ister misin?'", portrait: "rebecca", speaker: "Rebecca", options: [{ text: "Tabii, birlikte yüzmek harika olur.", effects: { rebecca: 10, lust: 5 } }, { text: "Yorgunum, başka zaman.", effects: { rebecca: -2 } }] }, { id: "villa_rebecca_2", text: "Rebecca: 'Villada baş başa bir akşam geçirelim mi?'", portrait: "rebecca", speaker: "Rebecca", options: [{ text: "Evet, baş başa kalmak güzel olur.", effects: { rebecca: 8, happy: 3 } }, { text: "Bugün olmaz.", effects: { rebecca: -2 } }] }, // Peter { id: "villa_peter_1", text: "Peter: 'Bahçede mangal yapalım mı?'", portrait: "peter", speaker: "Peter", options: [{ text: "Mangal harika olur!", effects: { peter: 10, happy: 4 } }, { text: "Başka zaman.", effects: { peter: -2 } }] }, { id: "villa_peter_2", text: "Peter: 'Villada birlikte film gecesi yapalım mı?'", portrait: "peter", speaker: "Peter", options: [{ text: "Evet, film gecesi yapalım.", effects: { peter: 8, happy: 3 } }, { text: "İstemiyorum.", effects: { peter: -2 } }] }, // Alex { id: "villa_alex_1", text: "Alex: 'Bu villada iş toplantısı yapmak isterim.'", portrait: "alex", speaker: "Alex", options: [{ text: "Tabii, toplantı yapabiliriz.", effects: { alex: 10, happy: 2 } }, { text: "Evde iş konuşmak istemiyorum.", effects: { alex: -2 } }] }, { id: "villa_alex_2", text: "Alex: 'Villanın manzarası harika, burada çalışmak isterim.'", portrait: "alex", speaker: "Alex", options: [{ text: "İstediğin zaman gelebilirsin.", effects: { alex: 8, honest: 2 } }, { text: "Evde yalnız kalmak istiyorum.", effects: { alex: -2 } }] }]; // --- Giselle'e özel sorular (yalnızca satın alındıysa gösterilecek) --- var giselleQuestions = [{ id: "giselle_intro", text: "Giselle: 'Mike, yeni bir çanta almak istiyorum. Bütçemiz yeterli mi?'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Tabii, hemen alalım. ($500 harca)", effects: { happy: 5 }, meta: { type: "giselle_spend", money: -500 } }, { text: "Şu an alamayız, bütçemiz kısıtlı.", effects: { happy: -5, honest: 5 }, meta: { type: "truth" } }] }, { id: "giselle_shopping", text: "Giselle: 'Alışverişe çıkalım mı? Birkaç şey almak istiyorum.'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Giselle'e para ver. ($300 harca)", effects: { happy: 5 }, meta: { type: "giselle_spend", money: -300 } }, { text: "Bugün alışveriş yok.", effects: { happy: -5 } }] }, { id: "giselle_dinner", text: "Giselle: 'Bu akşam dışarıda yemek yiyelim mi?'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Lüks restorana git. ($400 harca)", effects: { happy: 10, lust: 5 }, meta: { type: "giselle_spend", money: -400 } }, { text: "Evde yemek yapalım.", effects: { happy: -5 } }] }, { id: "giselle_gift", text: "Giselle: 'Bana hediye alır mısın?'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Pahalı bir kolye al. ($1000 harca)", effects: { happy: 10, lust: 5 }, meta: { type: "giselle_spend", money: -1000 } }, { text: "Küçük bir hediye al. ($100 harca)", effects: { happy: 3 }, meta: { type: "giselle_spend", money: -100 } }, { text: "Hediye almayacağım.", effects: { happy: -10 } }] }, { id: "giselle_jealous", text: "Giselle: 'Lisa ile çok vakit geçiriyorsun, kıskanıyorum.'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Giselle'e güven ver.", effects: { happy: 5, honest: 5 } }, { text: "Lisa ile görüşmeyi azalt.", effects: { happy: 2, lust: -2 } }] }, { id: "giselle_party", text: "Giselle: 'Hafta sonu partiye gidelim mi?'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Partiye git. ($200 harca)", effects: { happy: 5, lust: 5 }, meta: { type: "giselle_spend", money: -200 } }, { text: "Evde kalalım.", effects: { happy: -3 } }] }, { id: "giselle_baby", text: "Giselle: 'Bir bebek sahibi olmayı düşünür müsün?'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Evet, isterim.", effects: { happy: 10, lust: 5 }, meta: { type: "giselle_baby" } }, { text: "Henüz hazır değilim.", effects: { happy: -5 } }] }, { id: "giselle_trip", text: "Giselle: 'Birlikte tatile çıkalım mı?'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Tatile çık. ($1500 harca)", effects: { happy: 10, lust: 5 }, meta: { type: "giselle_spend", money: -1500 } }, { text: "Tatil için paramız yok.", effects: { happy: -5 } }] }, { id: "giselle_friends", text: "Giselle: 'Arkadaşlarımı davet edebilir miyim?'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Tabii, davet et.", effects: { happy: 5 } }, { text: "Hayır, bu akşam yalnız kalalım.", effects: { happy: -3 } }] }, { id: "giselle_shoes", text: "Giselle: 'Yeni ayakkabılar almak istiyorum.'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Ayakkabı al. ($250 harca)", effects: { happy: 5 }, meta: { type: "giselle_spend", money: -250 } }, { text: "Şu an alamayız.", effects: { happy: -3 } }] }, { id: "giselle_movie", text: "Giselle: 'Bu akşam sinemaya gidelim mi?'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Sinemaya git. ($100 harca)", effects: { happy: 5 }, meta: { type: "giselle_spend", money: -100 } }, { text: "Evde film izleyelim.", effects: { happy: 2 } }] }, { id: "giselle_dress", text: "Giselle: 'Yeni bir elbise almak istiyorum.'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Elbise al. ($350 harca)", effects: { happy: 5 }, meta: { type: "giselle_spend", money: -350 } }, { text: "Şu an alamayız.", effects: { happy: -3 } }] }, { id: "giselle_jewelry", text: "Giselle: 'Takı mağazasına gidelim mi?'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Takı al. ($200 harca)", effects: { happy: 5 }, meta: { type: "giselle_spend", money: -200 } }, { text: "Takı almayalım.", effects: { happy: -2 } }] }, { id: "giselle_spa", text: "Giselle: 'Birlikte spa'ya gidelim mi?'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Spa'ya git. ($400 harca)", effects: { happy: 7 }, meta: { type: "giselle_spend", money: -400 } }, { text: "Evde dinlenelim.", effects: { happy: 2 } }] }, { id: "giselle_phone", text: "Giselle: 'Yeni bir telefon almak istiyorum.'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Telefon al. ($1200 harca)", effects: { happy: 10 }, meta: { type: "giselle_spend", money: -1200 } }, { text: "Şu an alamayız.", effects: { happy: -5 } }] }, { id: "giselle_bag", text: "Giselle: 'Çantam eskidi, yenisini alabilir miyiz?'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Çanta al. ($300 harca)", effects: { happy: 5 }, meta: { type: "giselle_spend", money: -300 } }, { text: "Şu an alamayız.", effects: { happy: -3 } }] }, { id: "giselle_makeup", text: "Giselle: 'Kozmetik alışverişi yapalım mı?'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Kozmetik al. ($150 harca)", effects: { happy: 3 }, meta: { type: "giselle_spend", money: -150 } }, { text: "Hayır, gerek yok.", effects: { happy: -2 } }] }, { id: "giselle_jacket", text: "Giselle: 'Yeni bir ceket almak istiyorum.'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Ceket al. ($400 harca)", effects: { happy: 5 }, meta: { type: "giselle_spend", money: -400 } }, { text: "Şu an alamayız.", effects: { happy: -3 } }] }, { id: "giselle_ring", text: "Giselle: 'Yüzük bakmaya gidelim mi?'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Yüzük al. ($800 harca)", effects: { happy: 8 }, meta: { type: "giselle_spend", money: -800 } }, { text: "Yüzük almayalım.", effects: { happy: -3 } }] }, { id: "giselle_baby2", text: "Giselle: 'Bebek sahibi olmayı hâlâ düşünüyor musun?'", portrait: "giselle", speaker: "Giselle", options: [{ text: "Evet, isterim.", effects: { happy: 10, lust: 5 }, meta: { type: "giselle_baby" } }, { text: "Henüz hazır değilim.", effects: { happy: -5 } }] }]; // --- Ana story havuzu --- var story = [ // Lisa kahvaltı - düşük ilişki { id: "lisa_breakfast_low", text: "Lisa sabah kahvaltı hazırlamış ama aranız biraz soğuk. Mike ne der?", portrait: 'lisa', speaker: 'Lisa', mood: "sad", barCheck: { key: "lisa", max: 40 }, options: [{ text: "Yine mi aynı şey, biraz değişiklik yap.", effects: { lisa: -10, happy: -5 }, meta: { type: "truth" }, next: null }, { text: "Teşekkür etmeden geçiştir.", effects: { lisa: -5 }, meta: { type: "lie" }, next: null }] }, // Lisa kahvaltı - orta ilişki { id: "lisa_breakfast_mid", text: "Lisa sabah kahvaltı hazırlamış. Mike ne der?", portrait: 'lisa', speaker: 'Lisa', mood: "neutral", barCheck: { key: "lisa", min: 41, max: 80 }, regretTrigger: "lied", options: [{ text: "Çok güzel olmuş, teşekkür ederim.", effects: { lisa: 10, happy: 5 }, next: null }, { text: "Yine mi aynı şey, biraz değişiklik yap.", effects: { lisa: -10, happy: -5 }, meta: { type: "lie" }, next: null }] }, // Lisa kahvaltı - yüksek ilişki { id: "lisa_breakfast_high", text: "Lisa sabah kahvaltı hazırlamış, aranız çok iyi. Mike ne der?", portrait: 'lisa', speaker: 'Lisa', mood: "happy", barCheck: { key: "lisa", min: 81 }, options: [{ text: "Sana her gün teşekkür etsem az, harikasın.", effects: { lisa: 10, happy: 10 }, next: null }, { text: "Bugün de seninle kahvaltı yapmak çok güzel.", effects: { lisa: 5, happy: 5 }, next: null }] }, // Rebecca sabah mesaj - düşük ilişki { id: "rebecca_morning_low", text: "Rebecca sabah mesaj atıyor ama aranız biraz soğuk: 'Günaydın, öğle arasında buluşalım mı?'", portrait: 'rebecca', speaker: 'Rebecca', mood: "sad", barCheck: { key: "rebecca", max: 40 }, options: [{ text: "Şu an yoğunum, sonra konuşuruz.", effects: { rebecca: -5, honest: 5 }, meta: { type: "truth" }, next: null }, { text: "Kısa cevap ver.", effects: { rebecca: -5 }, meta: { type: "lie" }, next: null }] }, // Rebecca sabah mesaj - orta ilişki { id: "rebecca_morning_mid", text: "Rebecca sabah mesaj atıyor: 'Günaydın, öğle arasında buluşalım mı?'", portrait: 'rebecca', speaker: 'Rebecca', mood: "neutral", barCheck: { key: "rebecca", min: 41, max: 80 }, options: [{ text: "Tabii, öğle arasında buluşalım.", effects: { rebecca: 10, lust: 5, betray: 5 }, next: null }, { text: "Şu an yoğunum, sonra konuşuruz.", effects: { rebecca: -5, honest: 5 }, next: null }] }, // Rebecca sabah mesaj - yüksek ilişki { id: "rebecca_morning_high", text: "Rebecca sabah mesaj atıyor, aranız çok iyi: 'Günaydın yakışıklı, öğle arasında buluşalım mı?'", portrait: 'rebecca', speaker: 'Rebecca', mood: "happy", barCheck: { key: "rebecca", min: 81 }, options: [{ text: "Seni görmek için sabırsızlanıyorum.", effects: { rebecca: 10, lust: 10, betray: 10 }, next: null }, { text: "Bugün işim var ama akşam konuşalım.", effects: { rebecca: 5, honest: 5 }, next: null }] }, // ... (diğer orijinal story node'lar buraya eklenebilir, örnek olarak ilk iki olay çoğaltıldı) // 3 { text: "Patronun Alex seni sert bir şekilde eleştiriyor. Ne yaparsın?", portrait: 'alex', speaker: 'Alex', mood: "angry", options: [{ text: "Haklısınız, daha dikkatli olacağım.", effects: { alex: 10, honest: 5, happy: -5 }, next: null }, { text: "Bana fazla yükleniyorsunuz, adil değil.", effects: { alex: -10, happy: -5 }, next: null }] }, // --- Ava: New story questions for more variety --- { text: "Lisa ile alışverişe çıktınız. Lisa yeni bir elbise almak istiyor.", portrait: 'lisa', speaker: 'Lisa', options: [{ text: "Elbise almasına destek ol.", effects: { lisa: 10, happy: 5 } }, { text: "Bütçemiz kısıtlı, başka zaman alalım.", effects: { lisa: -5, honest: 5 } }] }, { text: "Rebecca iş yerinde sana bir sır veriyor.", portrait: 'rebecca', speaker: 'Rebecca', options: [{ text: "Sırrını sakla.", effects: { rebecca: 10, honest: 5 } }, { text: "Sırrı başkasına anlat.", effects: { rebecca: -10, betray: 10 } }] }, { text: "Peter ile futbol maçı izliyorsunuz.", portrait: 'peter', speaker: 'Peter', options: [{ text: "Beraber tezahürat yap.", effects: { peter: 10, happy: 5 } }, { text: "Maçtan sıkıldığını söyle.", effects: { peter: -5 } }] }, { text: "Alex yeni bir iş fırsatı sunuyor.", portrait: 'alex', speaker: 'Alex', options: [{ text: "Fırsatı kabul et.", effects: { alex: 10, happy: 5 } }, { text: "Reddet, mevcut işinden memnunsun.", effects: { alex: -5, honest: 5 } }] }, { text: "Lisa ile tartıştınız. Lisa üzgün.", portrait: 'lisa', speaker: 'Lisa', options: [{ text: "Özür dile.", effects: { lisa: 10, honest: 5 } }, { text: "Haklı olduğunu savun.", effects: { lisa: -10 } }] }, { text: "Rebecca ile sinemaya gitme planı yapıyorsun.", portrait: 'rebecca', speaker: 'Rebecca', options: [{ text: "Romantik bir film seç.", effects: { rebecca: 10, lust: 5 } }, { text: "Aksiyon filmi seç.", effects: { rebecca: 5 } }] }, { text: "Peter sana bir kitap öneriyor.", portrait: 'peter', speaker: 'Peter', options: [{ text: "Kitabı oku ve yorum yap.", effects: { peter: 10, honest: 5 } }, { text: "Kitabı okumadığını itiraf et.", effects: { peter: -5, honest: 5 } }] }, { text: "Alex ile iş seyahatine çıkıyorsun.", portrait: 'alex', speaker: 'Alex', options: [{ text: "Alex ile yakınlaş.", effects: { alex: 10, betray: 5 } }, { text: "Mesafeni koru.", effects: { alex: 5, honest: 5 } }] }, { text: "Lisa sana sürpriz bir doğum günü partisi hazırlıyor.", portrait: 'lisa', speaker: 'Lisa', options: [{ text: "Çok mutlu ol ve teşekkür et.", effects: { lisa: 10, happy: 10 } }, { text: "Sürprizleri sevmediğini söyle.", effects: { lisa: -5, honest: 5 } }] }, { text: "Rebecca ile bir tartışma yaşıyorsun.", portrait: 'rebecca', speaker: 'Rebecca', options: [{ text: "Barışmak için adım at.", effects: { rebecca: 10 } }, { text: "Tartışmayı uzat.", effects: { rebecca: -10 } }] }, { text: "Peter ile eski bir fotoğraf albümüne bakıyorsun.", portrait: 'peter', speaker: 'Peter', options: [{ text: "Güzel anıları hatırla.", effects: { peter: 10, happy: 5 } }, { text: "Geçmişi konuşmak istemediğini söyle.", effects: { peter: -5 } }] }, { text: "Alex iş yerinde seni övüyor.", portrait: 'alex', speaker: 'Alex', options: [{ text: "Teşekkür et.", effects: { alex: 10, happy: 5 } }, { text: "Mütevazı davran.", effects: { alex: 5 } }] }, { text: "Lisa ile birlikte yemek yapıyorsun.", portrait: 'lisa', speaker: 'Lisa', options: [{ text: "Birlikte eğlenerek yemek yap.", effects: { lisa: 10, happy: 5 } }, { text: "Yemek yapmayı sevmediğini söyle.", effects: { lisa: -5 } }] }, { text: "Rebecca yeni bir hobiye başlamak istiyor.", portrait: 'rebecca', speaker: 'Rebecca', options: [{ text: "Onu destekle.", effects: { rebecca: 10 } }, { text: "Hobisini gereksiz bul.", effects: { rebecca: -5 } }] }, { text: "Peter ile bir iş projesinde çalışıyorsun.", portrait: 'peter', speaker: 'Peter', options: [{ text: "Peter'ın fikirlerine değer ver.", effects: { peter: 10 } }, { text: "Kendi bildiğini yap.", effects: { peter: -5 } }] }, { text: "Alex ile bir anlaşmazlık yaşıyorsun.", portrait: 'alex', speaker: 'Alex', options: [{ text: "Uzlaşmacı ol.", effects: { alex: 10 } }, { text: "Kendi fikrinde ısrar et.", effects: { alex: -5 } }] }, // 3 { text: "Patronun Alex seni sert bir şekilde eleştiriyor. Ne yaparsın?", portrait: 'alex', speaker: 'Alex', mood: "angry", options: [{ text: "Haklısınız, daha dikkatli olacağım.", effects: { alex: 10, honest: 5, happy: -5 }, next: null }, { text: "Bana fazla yükleniyorsunuz, adil değil.", effects: { alex: -10, happy: -5 }, next: null }] }, // 4 { text: "Peter zor durumda olduğunu söylüyor. Ne yaparsın?", portrait: 'peter', speaker: 'Peter', mood: "sad", options: [{ text: "Yanındayım, neye ihtiyacın varsa söyle.", effects: { peter: 10, happy: 5 }, next: null }, { text: "Kendi işimle meşgulüm, üzgünüm.", effects: { peter: -10, happy: -5 }, next: null }] }, // 5 { text: "Lisa seninle dürüstçe konuşmak istiyor. Ne yaparsın?", portrait: 'lisa', speaker: 'Lisa', options: [{ text: "Tabii, ne söylemek istiyorsan dinliyorum.", effects: { lisa: 10, honest: 10 }, next: null }, { text: "Bunları konuşmak istemiyorum.", effects: { lisa: -10, honest: -10 }, next: null }] }, // 6 { text: "Rebecca ile ofiste samimi bir an yaşıyorsun. Lisa yanında.", portrait: 'rebecca', speaker: 'Rebecca', options: [{ text: "Lisa burada, sonra konuşalım.", effects: { rebecca: -5, honest: 5 }, next: null }, { text: "Hemen sana geliyorum.", effects: { rebecca: 10, lisa: -10, betray: 10 }, next: null }] }, // 7 { text: "Yorgunsun, Lisa dışarı çıkmak istiyor.", portrait: 'lisa', speaker: 'Lisa', options: [{ text: "Bugün yorgunum, evde kalalım.", effects: { lisa: -5, happy: -5 }, next: null }, { text: "Tamam, seninle dışarı çıkalım.", effects: { lisa: 10, happy: 5 }, next: null }] }, // 8 { text: "Alex önemli bir projeyi sana teslim etti.", portrait: 'alex', speaker: 'Alex', mood: "neutral", options: [{ text: "Gerçekçi zaman verirsek başarı şansı artar.", effects: { alex: 10, honest: 10 }, next: null }, { text: "Mümkün olduğunca hızlı yapacağım, sorun yok.", effects: { alex: -5, happy: 5 }, next: null }] }, // 9 { text: "Peter geçmişte yaptığın bir hatayı hatırlatıyor.", portrait: 'peter', speaker: 'Peter', mood: "angry", regretTrigger: "ignored_peter", options: [{ text: "Haklısın, özür dilerim.", effects: { peter: 10, honest: 10 }, next: null }, { text: "O günler geçti, unutalım.", effects: { peter: -10 }, meta: { ignoreRegret: true }, next: null }] }, // 10 { text: "Lisa bir sır sakladığını düşünüyor.", portrait: 'lisa', speaker: 'Lisa', regretTrigger: "betrayed_lisa", options: [{ text: "Sana her şeyi anlatacağım.", effects: { lisa: 10, honest: 10 }, next: null }, { text: "Beni yanlış anlıyorsun.", effects: { lisa: -10, honest: -10 }, meta: { type: "lie" }, next: null }] }, // 11 { text: "Rebecca ile iş çıkışı kafede buluşuyorsun.", portrait: 'rebecca', speaker: 'Rebecca', options: [{ text: "Rebecca ile samimi bir sohbet et.", effects: { rebecca: 10, lust: 10, betray: 5 }, next: null }, { text: "Kısa kesip eve git.", effects: { rebecca: -5, lisa: 5, honest: 5 }, next: null }] }, // 12 { text: "Alex seni fazla mesaiye bırakmak istiyor.", portrait: 'alex', speaker: 'Alex', mood: "neutral", options: [{ text: "Kabul et, işini bitir.", effects: { alex: 10, happy: -5 }, next: null }, { text: "Reddet, eve git.", effects: { alex: -10, lisa: 5, happy: 5 }, next: null }] }, // 13 { text: "Peter ile eski günlerden konuşuyorsun.", portrait: 'peter', speaker: 'Peter', mood: "happy", options: [{ text: "Duygusal bir anı paylaş.", effects: { peter: 10, happy: 5 }, next: null }, { text: "Geçmişi geçiştir.", effects: { peter: -5 }, next: null }] }, // 14 { text: "Lisa ile romantik bir akşam yemeği.", portrait: 'lisa', speaker: 'Lisa', options: [{ text: "Lisa'ya iltifat et.", effects: { lisa: 10, happy: 10, lust: 5 }, next: null }, { text: "Yemekle ilgilenme, telefona bak.", effects: { lisa: -10, happy: -5, lust: -5 }, next: null }] }, // 15 { text: "Rebecca işte sana yardım ediyor.", portrait: 'rebecca', speaker: 'Rebecca', options: [{ text: "Teşekkür et, birlikte çalış.", effects: { rebecca: 10, honest: 5 }, next: null }, { text: "Yardımı reddet.", effects: { rebecca: -5 }, next: null }] }, // 16 { text: "Alex işte bir hata buldu.", portrait: 'alex', speaker: 'Alex', mood: "angry", options: [{ text: "Hatanı kabul et.", effects: { alex: 5, honest: 10 }, next: null }, { text: "Suçu başkasına at.", effects: { alex: -10, honest: -10, betray: 10 }, next: null }] }, // 17 { text: "Peter ile tartıştın.", portrait: 'peter', speaker: 'Peter', mood: "angry", options: [{ text: "Barışmak için adım at.", effects: { peter: 10, honest: 5 }, next: null }, { text: "Görmezden gel.", effects: { peter: -10, happy: -5 }, next: null }] }, // 18 { text: "Lisa ile hafta sonu planı yapıyorsun.", portrait: 'lisa', speaker: 'Lisa', options: [{ text: "Birlikte sinemaya git.", effects: { lisa: 10, happy: 5 }, next: null }, { text: "Evde kalmayı teklif et.", effects: { lisa: -5, happy: 5 }, next: null }] }, // 19 { text: "Rebecca ile iş gezisine çıkıyorsun.", portrait: 'rebecca', speaker: 'Rebecca', options: [{ text: "Samimi davran.", effects: { rebecca: 10, lust: 10, betray: 5 }, next: null }, { text: "Mesafeni koru.", effects: { rebecca: -5, honest: 5 }, next: null }] }, // 20 { text: "Alex yeni bir görev veriyor.", portrait: 'alex', speaker: 'Alex', mood: "neutral", options: [{ text: "Görevi kabul et.", effects: { alex: 10, happy: 5 }, next: null }, { text: "Görevi reddet.", effects: { alex: -10, happy: -5 }, next: null }] }]; // --- State --- // Relationship values (0-100) var rel_lisa = 50; var rel_rebecca = 50; var rel_peter = 50; var rel_alex = 50; // Bars (0-100) var bar_happy = 50; var bar_honest = 50; var bar_lust = 50; var bar_betray = 50; // --- Shadow bar (0-100, hidden from player) --- var bar_shadow = 0; // Bar-based flags (for special scenes/endings) var flags = {}; // Track important past choices for memory mechanic var pastChoices = []; // Turn counter for time-based triggers var turnCount = 0; // --- Ava: Time, salary, baby, pregnancy, money mechanics --- var dayCount = 1; // 1-based, every 2 questions = 1 day var mikeSalary = 100; var mikeMoney = 0; var mikeBabyCount = 0; var lisaPregnant = false; var rebeccaPregnant = false; var gisellePregnant = false; var showLisaPregOption = false; var showRebeccaPregOption = false; var showGisellePregOption = false; var giselleUnlocked = false; // Satın alındı mı? var shopItemStates = [false, false, false, false]; // 0: Giselle, 1-3: diğerleri // --- UI Elements --- // Portrait var portraitNode = null; // Speaker name var speakerText = null; // Story text var storyText = null; // Option buttons var optionButtons = []; // Relationship bars var barNodes = {}; // Karakter portreleri ve ilişki dereceleri için UI var characterPortraits = []; var characterLabels = []; // --- Ava: UI for day, salary, money, baby count --- var dayText = null; var salaryText = null; var moneyText = null; var babyText = null; // --- Functions --- // getNextNode: uygun story node'unu bar değerine göre seç // --- Ava: Prevent same question from repeating within last 20, and add more questions --- var lastStoryIndices = []; function getNextNode() { // Tüm story node'larını karıştır var indices = []; for (var i = 0; i < story.length; i++) { indices.push(i); } // Fisher-Yates shuffle for (var i = indices.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = indices[i]; indices[i] = indices[j]; indices[j] = temp; } // Ava: Filter out nodes that were used in the last 20 var filteredIndices = []; for (var k = 0; k < indices.length; k++) { var idx = indices[k]; if (lastStoryIndices.indexOf(idx) === -1) { filteredIndices.push(idx); } } // If less than 5 available, allow all (reset) var useIndices = filteredIndices.length > 5 ? filteredIndices : indices; // --- Giselle: Eğer satın alındıysa, havuza Giselle sorularını da ekle --- // --- Whiskey: Eğer satın alındıysa, havuza Whiskey sorularını da ekle --- // --- Villa: Eğer satın alındıysa, havuza Villa event ve sorularını da ekle --- var pool = []; for (var k = 0; k < useIndices.length; k++) { var idx = useIndices[k]; var node = story[idx]; // Sadece Giselle alınmışsa Giselle soruları havuza eklenir if (node && node.portrait === "giselle" && !giselleUnlocked) continue; // Sadece Whiskey alınmışsa Whiskey soruları havuza eklenir if (node && node.portrait === "whiskey" && !whiskeyUnlocked) continue; // Villa eventleri ve soruları sadece villaUnlocked ise eklenir if (node && node.id && node.id.indexOf("villa_") === 0 && !villaUnlocked) continue; pool.push({ idx: idx, node: node }); } if (giselleUnlocked) { // Son 20'de olmayan Giselle sorularını da ekle for (var g = 0; g < giselleQuestions.length; g++) { var gq = giselleQuestions[g]; var gqId = "giselle_" + g; // Sadece son 20'de yoksa ekle var alreadyUsed = false; for (var h = 0; h < lastStoryIndices.length; h++) { if (story[lastStoryIndices[h]] && story[lastStoryIndices[h]].id === gq.id) alreadyUsed = true; } if (!alreadyUsed) { pool.push({ idx: -1, node: gq }); } } } if (whiskeyUnlocked) { // Son 20'de olmayan Whiskey sorularını da ekle for (var w = 0; w < whiskeyQuestions.length; w++) { var wq = whiskeyQuestions[w]; var wqId = "whiskey_" + w; var alreadyUsedW = false; for (var h = 0; h < lastStoryIndices.length; h++) { if (story[lastStoryIndices[h]] && story[lastStoryIndices[h]].id === wq.id) alreadyUsedW = true; } if (!alreadyUsedW) { pool.push({ idx: -1, node: wq }); } } } if (villaUnlocked) { // Son 20'de olmayan Villa invite eventlerini ekle for (var v = 0; v < villaInviteEvents.length; v++) { var ve = villaInviteEvents[v]; var alreadyUsedV = false; for (var h = 0; h < lastStoryIndices.length; h++) { if (story[lastStoryIndices[h]] && story[lastStoryIndices[h]].id === ve.id) alreadyUsedV = true; } if (!alreadyUsedV) { pool.push({ idx: -1, node: ve }); } } // Son 20'de olmayan Villa özel sorularını ekle for (var vq = 0; vq < villaSpecialQuestions.length; vq++) { var vsq = villaSpecialQuestions[vq]; var alreadyUsedVSQ = false; for (var h = 0; h < lastStoryIndices.length; h++) { if (story[lastStoryIndices[h]] && story[lastStoryIndices[h]].id === vsq.id) alreadyUsedVSQ = true; } if (!alreadyUsedVSQ) { pool.push({ idx: -1, node: vsq }); } } } // Her bir node'u sırayla kontrol et, barCheck varsa uygun olanı döndür for (var k = 0; k < pool.length; k++) { var idx = pool[k].idx; var node = pool[k].node; if (!node.options || node.options.length === 0) continue; if (node.barCheck) { var key = node.barCheck.key; var min = typeof node.barCheck.min === "number" ? node.barCheck.min : -Infinity; var max = typeof node.barCheck.max === "number" ? node.barCheck.max : Infinity; var val = 0; if (key === "lisa") val = rel_lisa;else if (key === "rebecca") val = rel_rebecca;else if (key === "peter") val = rel_peter;else if (key === "alex") val = rel_alex;else if (key === "happy") val = bar_happy;else if (key === "honest") val = bar_honest;else if (key === "lust") val = bar_lust;else if (key === "betray") val = bar_betray; if (val >= min && val <= max) { lastStoryIndices.push(idx); if (lastStoryIndices.length > 20) lastStoryIndices.shift(); return idx; } } else { lastStoryIndices.push(idx); if (lastStoryIndices.length > 20) lastStoryIndices.shift(); return idx; } } // Hiçbiri uygun değilse ilk node'u döndür lastStoryIndices.push(0); if (lastStoryIndices.length > 20) lastStoryIndices.shift(); return 0; } function resetGameState() { rel_lisa = 50; rel_rebecca = 50; rel_peter = 50; rel_alex = 50; bar_happy = 50; bar_honest = 50; bar_lust = 50; bar_betray = 50; bar_shadow = 0; flags = {}; pastChoices = []; turnCount = 0; currentNode = 0; // Reset dramatic system nextDramaticTurn = 4 + Math.floor(Math.random() * 3); dramaticHistory = []; if (game._dramaticShadow) { game.removeChild(game._dramaticShadow); game._dramaticShadow = null; } dayCount = 1; mikeSalary = 100; mikeMoney = 0; mikeBabyCount = 0; lisaPregnant = false; rebeccaPregnant = false; gisellePregnant = false; giselleUnlocked = false; whiskeyUnlocked = false; villaUnlocked = false; shopItemStates = [false, false, false, false]; if (storage) { storage.mikeMoney = 0; storage.mikeSalary = 100; storage.mikeBabyCount = 0; storage.dayCount = 1; storage.lisaPregnant = false; storage.rebeccaPregnant = false; storage.gisellePregnant = false; storage.giselleUnlocked = false; storage.whiskeyUnlocked = false; storage.villaUnlocked = false; } } function createUI() { // Portrait if (portraitNode) game.removeChild(portraitNode); portraitNode = LK.getAsset('mike', { anchorX: 0.5, anchorY: 0.5 }); // Mike portresini ve karakteri ekrana tam ortala portraitNode.x = 2048 / 2; portraitNode.y = 520; game.addChild(portraitNode); // --- Mike portresine titreme animasyonu ekle --- function shakePortrait(node) { if (!node) return; var origX = 2048 / 2; var origY = 520; function doShake() { // Rastgele küçük bir ofset (±8px) var dx = (Math.random() - 0.5) * 16; var dy = (Math.random() - 0.5) * 10; tween(node, { x: origX + dx, y: origY + dy }, { duration: 80, easing: tween.linear, onFinish: function onFinish() { tween(node, { x: origX, y: origY }, { duration: 80, easing: tween.linear, onFinish: function onFinish() { LK.setTimeout(doShake, 80 + Math.floor(Math.random() * 60)); } }); } }); } doShake(); } shakePortrait(portraitNode); // --- Eğer ilgili karakter portresi varsa ona da titreme ekle --- if (game.relatedPortraitNode) { var _shakeRelated = function shakeRelated() { if (!relNode.parent) return; // Silindiyse dur var dx = (Math.random() - 0.5) * 16; var dy = (Math.random() - 0.5) * 10; tween(relNode, { x: relOrigX + dx, y: relOrigY + dy }, { duration: 80, easing: tween.linear, onFinish: function onFinish() { tween(relNode, { x: relOrigX, y: relOrigY }, { duration: 80, easing: tween.linear, onFinish: function onFinish() { LK.setTimeout(_shakeRelated, 80 + Math.floor(Math.random() * 60)); } }); } }); }; var relNode = game.relatedPortraitNode; var relOrigX = relNode.x; var relOrigY = relNode.y; _shakeRelated(); } // Speaker (isim) biraz daha aşağıda if (speakerText) game.removeChild(speakerText); speakerText = new Text2('', { size: 64, fill: '#ffffff' }); speakerText.anchor.set(0.5, 0.5); speakerText.x = 2048 / 2; speakerText.y = 740; game.addChild(speakerText); // Story text (olay) biraz daha aşağıda if (storyText) game.removeChild(storyText); storyText = new Text2('', { size: 54, fill: '#ffffff', wordWrap: true, wordWrapWidth: 1800 }); storyText.anchor.set(0.5, 0); storyText.x = 2048 / 2; storyText.y = 830; game.addChild(storyText); // Relationship bars var barNames = [{ key: 'happy', label: 'Mutluluk', y: 1100, val: bar_happy }, { key: 'honest', label: 'Dürüstlük', y: 1180, val: bar_honest }, { key: 'lust', label: 'Şehvet', y: 1260, val: bar_lust }, { key: 'betray', label: 'İhanet', y: 1340, val: bar_betray }]; for (var i = 0; i < barNames.length; i++) { var b = barNames[i]; if (barNodes[b.key]) game.removeChild(barNodes[b.key]); var bar = new RelationshipBar(); bar.setType(b.key); bar.setValue(b.val); // Bar ismi ve yüzdeyi birlikte göster if (bar.label) bar.removeChild(bar.label); bar.label = new Text2(b.label + ' (' + b.val + '%)', { size: 36, fill: '#ffffff' }); bar.label.anchor.set(1, 0.5); bar.label.x = bar.maxWidth + 20; bar.label.y = 20; bar.addChild(bar.label); bar.x = 2048 / 2 - 200; bar.y = b.y; game.addChild(bar); barNodes[b.key] = bar; } // Karakter portreleri ve ilişki dereceleri (en altta) for (var i = 0; i < characterPortraits.length; i++) { game.removeChild(characterPortraits[i]); } for (var i = 0; i < characterLabels.length; i++) { game.removeChild(characterLabels[i]); } characterPortraits = []; characterLabels = []; var chars = [{ key: 'lisa', label: 'Lisa', rel: rel_lisa }, { key: 'rebecca', label: 'Rebecca', rel: rel_rebecca }, { key: 'peter', label: 'Peter', rel: rel_peter }, { key: 'alex', label: 'Alex', rel: rel_alex }]; var startX = 2048 / 2 - 400 - 60; var y = 2600; for (var i = 0; i < chars.length; i++) { var c = chars[i]; var portrait = LK.getAsset(c.key, { anchorX: 0.5, anchorY: 1 }); portrait.x = startX + i * 270; portrait.y = y; game.addChild(portrait); characterPortraits.push(portrait); var label = new Text2(c.label + ': ' + c.rel + '%', { size: 44, fill: '#ffffff' }); label.anchor.set(0.5, 0); label.x = portrait.x; label.y = y + 10; game.addChild(label); characterLabels.push(label); } // --- Ava: Add day, salary, money, baby count UI --- if (dayText) game.removeChild(dayText); if (salaryText) game.removeChild(salaryText); if (moneyText) game.removeChild(moneyText); if (babyText) game.removeChild(babyText); dayText = new Text2('Gün: ' + dayCount, { size: 54, fill: '#fff' }); dayText.anchor.set(0, 0); dayText.x = 120; dayText.y = 80; game.addChild(dayText); salaryText = new Text2('Maaş: $' + mikeSalary, { size: 54, fill: '#fff' }); salaryText.anchor.set(0, 0); salaryText.x = 120; salaryText.y = 150; game.addChild(salaryText); moneyText = new Text2('Para: $' + mikeMoney, { size: 54, fill: '#fff' }); moneyText.anchor.set(0, 0); moneyText.x = 120; moneyText.y = 220; game.addChild(moneyText); babyText = new Text2('Bebek: ' + mikeBabyCount, { size: 54, fill: '#fff' }); babyText.anchor.set(0, 0); babyText.x = 120; babyText.y = 290; game.addChild(babyText); // --- Ava: Show relationship options if eligible --- // Remove old relationship option buttons if any if (game._relOptionBtns) { for (var i = 0; i < game._relOptionBtns.length; i++) { game.removeChild(game._relOptionBtns[i]); } } game._relOptionBtns = []; // --- Shop/Store UI (right side, vertical) --- if (game._shopNodes) { for (var i = 0; i < game._shopNodes.length; i++) { game.removeChild(game._shopNodes[i]); } } game._shopNodes = []; var shopAssetIds = ['giselle', 'shop_item2', 'shop_item3', 'shop_item4']; var shopPrices = [10000, 2500, 50000, 7500]; var shopLabels = ['Giselle', 'Whiskey', 'Villa', 'Eşya 4']; var shopYStart = 1200; // moved even further down var shopSpacing = 450; // even more space between items // --- Villa state --- if (typeof villaUnlocked === "undefined") villaUnlocked = false; if (typeof whiskeyUnlocked === "undefined") whiskeyUnlocked = false; for (var i = 0; i < 4; i++) { var assetId = shopAssetIds[i]; var node = LK.getAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); node.x = 2048 - 120; node.y = shopYStart + i * shopSpacing; node.scale.x = node.scale.y = 1.0; // Shop items are passive (dimmed, not interactive) until purchased, then active if (shopItemStates[i]) { node.alpha = 1.0; node.interactive = false; node.buttonMode = false; } else { node.alpha = 0.5; node.interactive = true; node.buttonMode = true; } // Price label (above the item) var priceText = ""; if (i === 0) { priceText = "$10,000"; } else if (i === 1) { priceText = "$2,500"; } else if (i === 2) { priceText = "$50,000"; } else if (i === 3) { priceText = "$7,500"; } var priceLabel = new Text2(priceText, { size: 38, fill: '#ffe066', fontWeight: 'bold' }); priceLabel.anchor.set(0.5, 1); priceLabel.x = node.x; priceLabel.y = node.y - node.height / 2 - 12; game.addChild(priceLabel); game._shopNodes.push(priceLabel); // Name label (below the item) var label = new Text2(shopLabels[i], { size: 36, fill: '#fff', wordWrap: true, wordWrapWidth: 180 }); label.anchor.set(0.5, 0); label.x = node.x; label.y = node.y + node.height / 2 + 10; game.addChild(node); game.addChild(label); game._shopNodes.push(node, label); // Giselle buy logic if (i === 0 && !giselleUnlocked) { node.down = function () { if (mikeMoney >= 10000) { mikeMoney -= 10000; giselleUnlocked = true; shopItemStates[0] = true; // After purchase, make the item active (full alpha, not interactive) node.alpha = 1.0; node.interactive = false; node.buttonMode = false; updateBars(); createUI(); } else { // Not enough money, flash red tween(node, { alpha: 0.3 }, { duration: 120, onFinish: function onFinish() { tween(node, { alpha: 1 }, { duration: 120 }); } }); } }; } // Whiskey buy logic if (i === 1 && !whiskeyUnlocked) { node.down = function () { if (mikeMoney >= 2500) { mikeMoney -= 2500; whiskeyUnlocked = true; shopItemStates[1] = true; // After purchase, make the item active (full alpha, not interactive) node.alpha = 1.0; node.interactive = false; node.buttonMode = false; updateBars(); createUI(); } else { // Not enough money, flash red tween(node, { alpha: 0.3 }, { duration: 120, onFinish: function onFinish() { tween(node, { alpha: 1 }, { duration: 120 }); } }); } }; } // Villa buy logic if (i === 2 && !villaUnlocked) { node.down = function () { if (mikeMoney >= 50000) { mikeMoney -= 50000; villaUnlocked = true; shopItemStates[2] = true; // After purchase, make the item active (full alpha, not interactive) node.alpha = 1.0; node.interactive = false; node.buttonMode = false; updateBars(); createUI(); } else { tween(node, { alpha: 0.3 }, { duration: 120, onFinish: function onFinish() { tween(node, { alpha: 1 }, { duration: 120 }); } }); } }; } } // Lisa if (rel_lisa > 70 && !lisaPregnant) { var btnLisa = new OptionButton(); btnLisa.setText("Lisa ile ilişkiye gir"); btnLisa.x = 2048 - 400; btnLisa.y = 80; btnLisa.setCallback(function () { // %30 hamile kalma şansı if (Math.random() < 0.3) { lisaPregnant = true; showStoryNode(currentNode); } }); game.addChild(btnLisa); game._relOptionBtns.push(btnLisa); } // Rebecca if (rel_rebecca > 70 && !rebeccaPregnant) { var btnRebecca = new OptionButton(); btnRebecca.setText("Rebecca ile ilişkiye gir"); btnRebecca.x = 2048 - 400; btnRebecca.y = 220; btnRebecca.setCallback(function () { if (Math.random() < 0.3) { rebeccaPregnant = true; showStoryNode(currentNode); } }); game.addChild(btnRebecca); game._relOptionBtns.push(btnRebecca); } // Giselle if (giselleUnlocked && !gisellePregnant) { var btnGiselle = new OptionButton(); btnGiselle.setText("Giselle ile ilişkiye gir"); btnGiselle.x = 2048 - 400; btnGiselle.y = 360; btnGiselle.setCallback(function () { if (Math.random() < 0.3) { gisellePregnant = true; showStoryNode(currentNode); } }); game.addChild(btnGiselle); game._relOptionBtns.push(btnGiselle); } } function updateBars() { if (typeof villaUnlocked !== "undefined" && villaUnlocked && bar_happy < 80) { bar_happy = 80; } barNodes['happy'].setValue(bar_happy); barNodes['honest'].setValue(bar_honest); barNodes['lust'].setValue(bar_lust); barNodes['betray'].setValue(bar_betray); // Bar isimleri ve yüzdeleri birlikte güncellensin barNodes['happy'].label.setText('Mutluluk (' + bar_happy + '%)'); barNodes['honest'].label.setText('Dürüstlük (' + bar_honest + '%)'); barNodes['lust'].label.setText('Şehvet (' + bar_lust + '%)'); barNodes['betray'].label.setText('İhanet (' + bar_betray + '%)'); // Karakter ilişki dereceleri güncellensin var rels = [rel_lisa, rel_rebecca, rel_peter, rel_alex]; var _loop = function _loop() { names = ['Lisa', 'Rebecca', 'Peter', 'Alex']; label = characterLabels[i]; prevText = label.text; newText = names[i] + ': ' + rels[i] + '%'; // Değer değiştiyse animasyon başlat if (prevText !== newText) { // Son değeri bul prevVal = 0; match = prevText && prevText.match(/: (\-?\d+)%/); if (match) prevVal = parseInt(match[1]); newVal = rels[i]; // Pozitif veya negatif değişim: sadece etkilenen karakter titresin if (newVal > prevVal || newVal < prevVal) { // Sadece ilişki değeri değişen karakter titresin portrait = characterPortraits[i]; if (portrait) { var _doShakeChar = function doShakeChar() { if (!portrait.parent || shakeCount >= 6) { // Titreme bitti, orijinal konuma dön portrait.x = origX; portrait.y = origY; return; } var dx = (Math.random() - 0.5) * 16; var dy = (Math.random() - 0.5) * 10; tween(portrait, { x: origX + dx, y: origY + dy }, { duration: 50, easing: tween.linear, onFinish: function onFinish() { tween(portrait, { x: origX, y: origY }, { duration: 50, easing: tween.linear, onFinish: function onFinish() { shakeCount++; LK.setTimeout(_doShakeChar, 10); } }); } }); }; // Titreme animasyonu uygula origX = portrait.x; origY = portrait.y; shakeCount = 0; _doShakeChar(); } } if (newVal > prevVal) { if (label.style) label.style.fill = '#00ff00'; tween(label, { alpha: 0.3 }, { duration: 120, easing: tween.linear, onFinish: function (lbl) { tween(lbl, { alpha: 1 }, { duration: 120, easing: tween.linear, onFinish: function (lbl2) { if (lbl2.style) lbl2.style.fill = '#ffffff'; }.bind(null, label) }); }.bind(null, label) }); } else if (newVal < prevVal) { if (label.style) label.style.fill = '#ff2222'; tween(label, { alpha: 0.3 }, { duration: 120, easing: tween.linear, onFinish: function (lbl) { tween(lbl, { alpha: 1 }, { duration: 120, easing: tween.linear, onFinish: function (lbl2) { if (lbl2.style) lbl2.style.fill = '#ffffff'; }.bind(null, label) }); }.bind(null, label) }); } } label.setText(newText); }, names, label, prevText, newText, prevVal, match, newVal, portrait, origX, origY, shakeCount; for (var i = 0; i < characterLabels.length; i++) { _loop(); } // --- Ava: Update day, salary, money, baby count UI --- if (dayText) dayText.setText('Gün: ' + dayCount); if (salaryText) salaryText.setText('Maaş: $' + mikeSalary); if (moneyText) moneyText.setText('Para: $' + mikeMoney); if (babyText) babyText.setText('Bebek: ' + mikeBabyCount); // Refresh relationship option buttons if (typeof createUI === "function") { // Only refresh if UI is visible (avoid infinite loop) if (game && typeof game._relOptionBtns !== "undefined") { createUI(); } } } function showStoryNode(idx) { // Remove old option buttons for (var i = 0; i < optionButtons.length; i++) { game.removeChild(optionButtons[i]); } optionButtons = []; // Dramatic choice injection: if turnCount >= nextDramaticTurn, show dramatic choice instead if (typeof nextDramaticTurn !== "undefined" && turnCount >= nextDramaticTurn) { showDramaticChoice(); return; } var node = story[idx]; // Portrait if (portraitNode) { if (node.portrait && LK.getAsset(node.portrait, {})) { portraitNode.texture = LK.getAsset(node.portrait, {}).texture; } // Mood-based tint or background for Lisa, Rebecca, Mike, Peter, Alex if (node.mood && (node.portrait === "lisa" || node.portrait === "rebecca" || node.portrait === "mike" || node.portrait === "peter" || node.portrait === "alex")) { // Mood to tint mapping var moodTints = { happy: 0x7ed321, sad: 0x4a90e2, angry: 0xd0021b, neutral: 0xffffff }; var tint = moodTints[node.mood] !== undefined ? moodTints[node.mood] : 0xffffff; portraitNode.tint = tint; } else { portraitNode.tint = 0xffffff; } // Remove any previous related character portrait if (game.relatedPortraitNode) { game.removeChild(game.relatedPortraitNode); game.relatedPortraitNode = null; } // If the node is about a character other than Mike, show that character next to Mike if (node.portrait && node.portrait !== "mike" && (node.portrait === "lisa" || node.portrait === "rebecca" || node.portrait === "peter" || node.portrait === "alex")) { var relatedPortrait = LK.getAsset(node.portrait, { anchorX: 0.5, anchorY: 0.5 }); // Place to the right of Mike, with a small gap relatedPortrait.x = portraitNode.x + portraitNode.width / 2 + relatedPortrait.width / 2 + 40; relatedPortrait.y = portraitNode.y; // Mood tint for related portrait if (node.mood) { var moodTints = { happy: 0x7ed321, sad: 0x4a90e2, angry: 0xd0021b, neutral: 0xffffff }; relatedPortrait.tint = moodTints[node.mood] !== undefined ? moodTints[node.mood] : 0xffffff; } else { relatedPortrait.tint = 0xffffff; } game.addChild(relatedPortrait); game.relatedPortraitNode = relatedPortrait; } else { if (game.relatedPortraitNode) { game.removeChild(game.relatedPortraitNode); game.relatedPortraitNode = null; } } } // Speaker if (speakerText) { speakerText.setText(node.speaker ? node.speaker : ''); } // Story text if (storyText) { // --- Hatırlatma ve Gölgeli Vicdan Mekanizması --- // 1. Eğer bu node bir regretTrigger içeriyorsa ve geçmişte ilgili regretLabel ile bir seçim yapıldıysa, iç ses/rüya olarak göster if (node.regretTrigger && pastChoices.indexOf(node.regretTrigger) !== -1) { // Vicdan sahnesi: iç ses veya rüya efektiyle göster var regretTexts = { "lied": "Gece rüyanda, Lisa'nın sana 'Bana neden yalan söyledin?' dediğini duyuyorsun. Vicdanın sızlıyor.", "betrayed_lisa": "Bir an için Lisa'nın gözlerinde hayal kırıklığını görüyorsun. İç sesin: 'Ona ihanet ettin.'", "ignored_peter": "Peter'ın üzgün bakışları aklından çıkmıyor. İç sesin: 'Dostunu yalnız bıraktın.'" }; var regretText = regretTexts[node.regretTrigger] || "Geçmişteki bir kararın gölgesi seni rahatsız ediyor."; storyText.setText(regretText + "\n\n(" + node.text + ")"); // Fade efekt: metni kısa süreliğine yarı saydam göster storyText.alpha = 0.5; tween(storyText, { alpha: 1 }, { duration: 1200, easing: tween.easeOut }); } else if ( // Yalancı Hafıza: Eğer honest bar düşükse ve geçmişte yalan söylendiyse, yanlış hatırlama metni göster bar_honest <= 30 && pastChoices.indexOf("lied") !== -1 && (node.id === "lisa_breakfast_mid" || node.id === "lisa_breakfast_high" || node.id === "lisa_breakfast_low")) { // Yalancı hafıza: Oyuncuya yanlış bilgi ver storyText.setText("Mike sanki o gün Lisa'ya doğruyu söylediğini hatırlıyordu... ama aslında yalan söylemişti.\n\n(" + node.text + ")"); storyText.alpha = 0.7; tween(storyText, { alpha: 1 }, { duration: 1200, easing: tween.easeOut }); } else if (node.id === "lisa_breakfast_mid" && pastChoices.indexOf("lied") !== -1) { storyText.setText("Lisa sana biraz mesafeli bakıyor. Geçmişteki yalanların etkisi sürüyor."); } else { storyText.setText(node.text); } } // Option buttons // --- Timed Choice Mechanism: If node.timedChoice is set, start a timer and auto-select if no choice is made --- var timedChoiceTimeout = null; var timedChoiceBar = null; if (node.options && node.options.length > 0) { // If previous timer exists, clear it if (game._timedChoiceTimeout) { LK.clearTimeout(game._timedChoiceTimeout); game._timedChoiceTimeout = null; } if (game._timedChoiceBar) { game.removeChild(game._timedChoiceBar); game._timedChoiceBar = null; } // If this node is a crisis/timed scene, e.g. node.timedChoice: { seconds: 5, default: 1 } var isTimed = node.timedChoice && typeof node.timedChoice.seconds === "number"; var timedSeconds = isTimed ? node.timedChoice.seconds : 0; var timedDefault = isTimed ? typeof node.timedChoice["default"] === "number" ? node.timedChoice["default"] : 0 : 0; var timedStart = Date.now(); var timedBarWidth = 900; var timedBarHeight = 24; var timedBarY = 1700 + node.options.length * 180 + 40; // Option button creation for (var i = 0; i < node.options.length; i++) { var opt = node.options[i]; // --- Requirements check --- var meetsReq = true; if (opt.requirements) { for (var key in opt.requirements) { var val = opt.requirements[key]; // Check current bar/relationship value var current = 0; if (key === 'lisa') current = rel_lisa;else if (key === 'rebecca') current = rel_rebecca;else if (key === 'peter') current = rel_peter;else if (key === 'alex') current = rel_alex;else if (key === 'happy') current = bar_happy;else if (key === 'honest') current = bar_honest;else if (key === 'lust') current = bar_lust;else if (key === 'betray') current = bar_betray; if (current < val) { meetsReq = false; break; } } } var btn = new OptionButton(); // --- Bilinmeyen Seçim Sistemi: option'a hiddenByBar eklendiyse ve bar yeterli değilse gizle --- var showAsHidden = false; if (opt.hiddenByBar) { // hiddenByBar: { key: 'honest', min: 60 } veya { key: 'betray', min: 40 } var barKey = opt.hiddenByBar.key; var minVal = typeof opt.hiddenByBar.min === "number" ? opt.hiddenByBar.min : 0; var currentVal = 0; if (barKey === 'lisa') currentVal = rel_lisa;else if (barKey === 'rebecca') currentVal = rel_rebecca;else if (barKey === 'peter') currentVal = rel_peter;else if (barKey === 'alex') currentVal = rel_alex;else if (barKey === 'happy') currentVal = bar_happy;else if (barKey === 'honest') currentVal = bar_honest;else if (barKey === 'lust') currentVal = bar_lust;else if (barKey === 'betray') currentVal = bar_betray; if (currentVal < minVal) showAsHidden = true; } if (showAsHidden) { btn.setText("???"); btn.bg.tint = 0x888888; btn.text.style.fill = '#bbbbbb'; btn.setCallback(function () {}); // No-op } else { btn.setText(opt.text); // If requirements not met, disable and gray out if (!meetsReq) { btn.bg.tint = 0x888888; btn.text.style.fill = '#bbbbbb'; btn.setCallback(function () {}); // No-op } else { btn.setCallback(function (opt, btnIdx) { return function () { // If a timed choice is running, clear the timer and bar if (game._timedChoiceTimeout) { LK.clearTimeout(game._timedChoiceTimeout); game._timedChoiceTimeout = null; } if (game._timedChoiceBar) { game.removeChild(game._timedChoiceBar); game._timedChoiceBar = null; } applyEffects(opt.effects, opt.meta); // Her zaman random bir sonraki soru seç, ama bar değerine göre uygun versiyonu seç var available = []; for (var j = 0; j < story.length; j++) { if (story[j].options && story[j].options.length > 0) available.push(j); } if (available.length > 0) { // getNextNode fonksiyonu ile uygun node'u seç var nextIdx = getNextNode(); currentNode = nextIdx; showStoryNode(currentNode); } else { // Oyun bitti, son ekranı göster showEnding(); } }; }(opt, i)); } } btn.x = 2048 / 2; btn.y = 1700 + i * 180; game.addChild(btn); optionButtons.push(btn); } // If this is a timed choice, show a timer bar and auto-select after timeout if (isTimed) { // Create a timer bar (background and fill) var barBg = LK.getAsset('bar_bg', { anchorX: 0.5, anchorY: 0.5 }); barBg.width = timedBarWidth; barBg.height = timedBarHeight; barBg.x = 2048 / 2; barBg.y = timedBarY; var barFill = LK.getAsset('bar_fill_betray', { anchorX: 0.5, anchorY: 0.5 }); barFill.width = timedBarWidth; barFill.height = timedBarHeight; barFill.x = 2048 / 2; barFill.y = timedBarY; // Add to game game.addChild(barBg); game.addChild(barFill); // Store for cleanup game._timedChoiceBar = barBg; game._timedChoiceBarFill = barFill; // Animate the bar fill var updateTimerBar = function updateTimerBar() { var elapsed = (Date.now() - timedStart) / 1000; var remain = Math.max(0, timedSeconds - elapsed); var ratio = remain / timedSeconds; barFill.width = timedBarWidth * ratio; if (ratio <= 0) { barFill.width = 0; } }; // Per-frame update for timer bar var timerBarInterval = LK.setInterval(function () { if (!game._timedChoiceBarFill) { LK.clearInterval(timerBarInterval); return; } updateTimerBar(); }, 50); // Timeout: auto-select default option game._timedChoiceTimeout = LK.setTimeout(function () { // Only trigger if still on this node if (game._timedChoiceBar) { // Simulate click on default option if (optionButtons[timedDefault] && typeof optionButtons[timedDefault].down === "function") { optionButtons[timedDefault].down(); } // Clean up timer bar if (game._timedChoiceBar) { game.removeChild(game._timedChoiceBar); game._timedChoiceBar = null; } if (game._timedChoiceBarFill) { game.removeChild(game._timedChoiceBarFill); game._timedChoiceBarFill = null; } LK.clearInterval(timerBarInterval); game._timedChoiceTimeout = null; } }, timedSeconds * 1000); } } } function applyEffects(effects, meta) { if (!effects) return; // --- Memory mechanic: record important choices --- // Example: If the player kisses Lisa, lies to Rebecca, etc. // We'll record meta.memoryLabel if present, otherwise try to infer from meta/type if (meta && meta.memoryLabel) { pastChoices.push(meta.memoryLabel); } else if (meta && meta.type === "lie") { pastChoices.push("lied"); // Regretful: lying is a regret } else if (meta && meta.type === "truth") { pastChoices.push("told_truth"); } // Regretful: betray Lisa if (typeof effects.lisa === 'number' && effects.lisa < 0 && typeof effects.betray === 'number' && effects.betray > 0) { pastChoices.push("betrayed_lisa"); } // Regretful: ignore Peter if (typeof effects.peter === 'number' && effects.peter < 0 && meta && meta.ignoreRegret) { pastChoices.push("ignored_peter"); } // Sadece yüzde 1 artıp azalsın if (typeof effects.lisa === 'number') rel_lisa = Math.max(0, Math.min(100, rel_lisa + (effects.lisa > 0 ? 1 : effects.lisa < 0 ? -1 : 0))); if (typeof effects.rebecca === 'number') rel_rebecca = Math.max(0, Math.min(100, rel_rebecca + (effects.rebecca > 0 ? 1 : effects.rebecca < 0 ? -1 : 0))); if (typeof effects.peter === 'number') rel_peter = Math.max(0, Math.min(100, rel_peter + (effects.peter > 0 ? 1 : effects.peter < 0 ? -1 : 0))); if (typeof effects.alex === 'number') rel_alex = Math.max(0, Math.min(100, rel_alex + (effects.alex > 0 ? 1 : effects.alex < 0 ? -1 : 0))); if (typeof effects.happy === 'number') { bar_happy = Math.max(0, Math.min(100, bar_happy + (effects.happy > 0 ? 1 : effects.happy < 0 ? -1 : 0))); if (typeof villaUnlocked !== "undefined" && villaUnlocked && bar_happy < 80) { bar_happy = 80; } } if (typeof effects.honest === 'number') bar_honest = Math.max(0, Math.min(100, bar_honest + (effects.honest > 0 ? 1 : effects.honest < 0 ? -1 : 0))); if (typeof effects.lust === 'number') bar_lust = Math.max(0, Math.min(100, bar_lust + (effects.lust > 0 ? 1 : effects.lust < 0 ? -1 : 0))); if (typeof effects.betray === 'number') bar_betray = Math.max(0, Math.min(100, bar_betray + (effects.betray > 0 ? 1 : effects.betray < 0 ? -1 : 0))); // --- Villa davet event: karakterle ilişkiyi %15 artır (etki zaten effects ile geliyor, ama burada ek bir kontrol de eklenebilir) --- if (meta && meta.type === "villa_invite" && typeof meta.character === "string") { if (meta.character === "lisa") rel_lisa = Math.min(100, rel_lisa + 15); if (meta.character === "rebecca") rel_rebecca = Math.min(100, rel_rebecca + 15); if (meta.character === "peter") rel_peter = Math.min(100, rel_peter + 15); if (meta.character === "alex") rel_alex = Math.min(100, rel_alex + 15); } // --- Giselle para harcama ve hamilelik --- if (meta && meta.type === "giselle_spend" && typeof meta.money === "number") { mikeMoney = Math.max(0, mikeMoney + meta.money); } // --- Whiskey para harcama --- if (meta && meta.type === "whiskey_spend" && typeof meta.money === "number") { mikeMoney = Math.max(0, mikeMoney + meta.money); } if (meta && meta.type === "giselle_baby" && giselleUnlocked && !gisellePregnant) { if (Math.random() < 0.3) { gisellePregnant = true; // Bebek doğumu bir sonraki günlerde gerçekleşecek } } // --- Shadow bar logic: increase/decrease based on hidden triggers --- // Betrayal, repeated lies, or negative choices increase shadow bar if (meta && meta.type === "lie" || typeof effects.betray === 'number' && effects.betray > 0) { bar_shadow = Math.max(0, Math.min(100, bar_shadow + 5)); } // If player is honest or makes a positive choice, shadow bar may decrease if (meta && meta.type === "truth" || typeof effects.honest === 'number' && effects.honest > 0) { bar_shadow = Math.max(0, bar_shadow - 2); } // If player ignores Peter or Lisa (meta.ignoreRegret), shadow bar increases if (meta && meta.ignoreRegret) { bar_shadow = Math.max(0, Math.min(100, bar_shadow + 3)); } // --- Honest bar penalty for repeated lies --- if (meta && meta.type === "lie") { // Lying reduces honest bar by 2 (or 1 if already low) bar_honest = Math.max(0, bar_honest - (bar_honest > 10 ? 2 : 1)); } // --- Relationship Cross Effects --- applyCrossEffects(effects, meta); updateBars(); // --- Turn-based trigger system --- // Increase turn count on every choice turnCount++; // --- Ava: Advance time every 2 turns (1 day = 2 questions) --- if (turnCount % 2 === 0) { dayCount++; // Mike maaş alır mikeMoney += mikeSalary; // Alex ile ilişki > 70 ise maaş +50 if (rel_alex > 70) { mikeSalary += 50; } // Alex ile ilişki < 30 ise maaş -20 if (rel_alex < 30) { mikeSalary = Math.max(0, mikeSalary - 20); } // Peter ile ilişki > 70 ise mutluluk +1 if (rel_peter > 70) { bar_happy = Math.min(100, bar_happy + 1); } // Lisa hamile ise doğum (her gün %10 ihtimal) if (lisaPregnant && Math.random() < 0.1) { mikeBabyCount++; lisaPregnant = false; } // Rebecca hamile ise doğum (her gün %10 ihtimal) if (rebeccaPregnant && Math.random() < 0.1) { mikeBabyCount++; rebeccaPregnant = false; } // Giselle hamile ise doğum (her gün %10 ihtimal) if (gisellePregnant && Math.random() < 0.1) { mikeBabyCount++; gisellePregnant = false; } // Save to storage storage.mikeMoney = mikeMoney; storage.mikeSalary = mikeSalary; storage.mikeBabyCount = mikeBabyCount; storage.dayCount = dayCount; storage.lisaPregnant = lisaPregnant; storage.rebeccaPregnant = rebeccaPregnant; // Update UI updateBars(); } // --- Dış Etki Mekanizması: Lust bar 3 tur boyunca yüksekse otomatik karar --- // Son 3 turdaki lust bar değerlerini takip et if (!flags.lustHistory) flags.lustHistory = []; flags.lustHistory.push(bar_lust); if (flags.lustHistory.length > 3) flags.lustHistory.shift(); // Eğer son 3 turda lust barı 70 ve üzeriyse, otomatik bir karar tetiklenir (ör: irade kaybı) if (flags.lustHistory.length === 3 && flags.lustHistory[0] >= 70 && flags.lustHistory[1] >= 70 && flags.lustHistory[2] >= 70 && !flags.lustAutoDecision) { flags.lustAutoDecision = true; // Oyuncunun kontrolü dışında bir olay: Rebecca ile yakınlaşma if (storyText) { storyText.setText("Mike, arzularına yenik düşüyor ve Rebecca'ya karşı koyamıyor. (Dış etki: İrade kaybı)"); storyText.alpha = 0.7; tween(storyText, { alpha: 1 }, { duration: 1200, easing: tween.easeOut }); } // Bar ve ilişkilerde otomatik değişiklikler rel_rebecca = Math.min(100, rel_rebecca + 5); bar_lust = Math.min(100, bar_lust + 5); bar_betray = Math.min(100, bar_betray + 5); updateBars(); // Sonraki node'a otomatik geçiş (Rebecca ile ilgili bir sahneye öncelik ver) var rebeccaIdx = -1; for (var i = 0; i < story.length; i++) { if (story[i].portrait === "rebecca" && story[i].options && story[i].options.length > 0) { rebeccaIdx = i; break; } } if (rebeccaIdx !== -1) { currentNode = rebeccaIdx; LK.setTimeout(function () { showStoryNode(currentNode); }, 1800); return; } } // Zamana bağlı özel rüya sahnesi tetikleyici örneği if (turnCount > 15 && bar_lust > 60 && !flags["specialDreamTriggered"]) { flags["specialDreamTriggered"] = true; showEnding("Mike, arzularının peşinden sürüklendiği özel bir rüya görüyor. (Zamana bağlı özel sahne)"); return; } // --- Bar-based flag system --- // Example: if betrayal bar reaches 80 or more, set betrayalUnlocked flag if (bar_betray >= 80) { flags["betrayalUnlocked"] = true; } if (bar_honest >= 90) { flags["honestyMaster"] = true; } if (bar_lust >= 90) { flags["lustHigh"] = true; } if (bar_happy >= 90) { flags["happinessPeak"] = true; } if (rel_lisa >= 90) { flags["lisaBond"] = true; } if (rel_rebecca >= 90) { flags["rebeccaBond"] = true; } if (rel_peter >= 90) { flags["peterBond"] = true; } if (rel_alex >= 90) { flags["alexBond"] = true; } // --- Shadow bar event triggers (hidden, unexpected events) --- if (!flags.shadow30 && bar_shadow >= 30) { flags.shadow30 = true; // Ani içsel monolog: Mike'ın öfke patlaması if (storyText) { storyText.setText("Mike'ın içinde bir öfke kabarıyor. (İç ses: 'Bazen her şeyi yakıp yıkmak istiyorum...')\n\n" + (storyText.text || "")); storyText.alpha = 0.7; tween(storyText, { alpha: 1 }, { duration: 1000, easing: tween.easeOut }); } } if (!flags.shadow60 && bar_shadow >= 60) { flags.shadow60 = true; // Mike'ın beklenmedik bir şekilde bağırması (oyuncuya yansır) if (storyText) { storyText.setText("Mike aniden bağırıyor: 'YETER ARTIK!'\n\n" + (storyText.text || "")); storyText.alpha = 0.7; tween(storyText, { alpha: 1 }, { duration: 1000, easing: tween.easeOut }); } // Portrait kırmızıya döner, kısa süreliğine if (portraitNode) { var oldTint = portraitNode.tint; portraitNode.tint = 0xd0021b; tween(portraitNode, { tint: oldTint }, { duration: 1200, easing: tween.easeOut }); } } if (!flags.shadow90 && bar_shadow >= 90) { flags.shadow90 = true; // Mike'ın içsel çöküşü: iç ses, portre fade out if (storyText) { storyText.setText("Mike'ın zihni karanlığa gömülüyor. (İç ses: 'Artık kendimi tanıyamıyorum...')\n\n" + (storyText.text || "")); storyText.alpha = 0.5; tween(storyText, { alpha: 1 }, { duration: 1500, easing: tween.easeOut }); } if (portraitNode) { tween(portraitNode, { alpha: 0.2 }, { duration: 1500, easing: tween.easeOut }); } } // Check for fail/win conditions if (bar_happy <= 0) { showEnding('Mutluluk sıfırlandı. Mike depresyona girdi.'); return; } if (bar_honest <= 0) { showEnding('Dürüstlük sıfırlandı. Mike yalanlarla dolu bir hayata saplandı.'); return; } if (bar_lust <= 0) { showEnding('Şehvet sıfırlandı. Mike hayattan keyif alamıyor.'); return; } if (bar_betray >= 100) { showEnding('İhanet %100 oldu. Mike ilişkilerini kaybetti.'); return; } } // İlişki çaprazlama mekanizması: Lisa ile yakınlık artınca Rebecca kıskanır, Rebecca ile yakınlık artınca Lisa üzülür, vs. function applyCrossEffects(effects, meta) { // Lisa ile yakınlık artarsa Rebecca'nın ilişkisi biraz azalır (kıskançlık) if (typeof effects.lisa === 'number' && effects.lisa > 0) { // Lisa ile +1 yakınlık, Rebecca -1 rel_rebecca = Math.max(0, rel_rebecca - 1); } // Rebecca ile yakınlık artarsa Lisa'nın ilişkisi biraz azalır (kıskançlık) if (typeof effects.rebecca === 'number' && effects.rebecca > 0) { rel_lisa = Math.max(0, rel_lisa - 1); } // Lisa ile yakınlık azalırsa Rebecca biraz mutlu olur (rekabet) if (typeof effects.lisa === 'number' && effects.lisa < 0) { rel_rebecca = Math.min(100, rel_rebecca + 1); } // Rebecca ile yakınlık azalırsa Lisa biraz mutlu olur (rekabet) if (typeof effects.rebecca === 'number' && effects.rebecca < 0) { rel_lisa = Math.min(100, rel_lisa + 1); } // Betray (ihanet) barı artarsa Lisa ve Rebecca'nın ilişkisi biraz azalır if (typeof effects.betray === 'number' && effects.betray > 0) { rel_lisa = Math.max(0, rel_lisa - 1); rel_rebecca = Math.max(0, rel_rebecca - 1); } // Lust barı çok artarsa (ör: Rebecca ile), Lisa'nın ilişkisi biraz azalır if (typeof effects.lust === 'number' && effects.lust > 0) { rel_lisa = Math.max(0, rel_lisa - 1); } // Happy barı çok azalırsa, tüm ilişkiler biraz azalır if (typeof effects.happy === 'number' && effects.happy < 0) { rel_lisa = Math.max(0, rel_lisa - 1); rel_rebecca = Math.max(0, rel_rebecca - 1); rel_peter = Math.max(0, rel_peter - 1); rel_alex = Math.max(0, rel_alex - 1); } } function showEnding(msg) { // Remove option buttons for (var i = 0; i < optionButtons.length; i++) { game.removeChild(optionButtons[i]); } optionButtons = []; // --- Animated, bar-specific game over --- // Determine which bar triggered game over var endingType = null; if (typeof msg === "string") { if (msg.indexOf("Mutluluk") !== -1) endingType = "happy";else if (msg.indexOf("Dürüstlük") !== -1) endingType = "honest";else if (msg.indexOf("Şehvet") !== -1) endingType = "lust";else if (msg.indexOf("İhanet") !== -1) endingType = "betray"; } // Default: Mike portrait var portraitKey = "mike"; var endingText = msg; var mood = "sad"; var crossX = null; // Custom portrait and text for each bar if (endingType === "betray") { // Mike gözaltına alınıyor portraitKey = "mike"; endingText = "SON: Mike ihanetin bedelini ödedi ve gözaltına alındı.\n\nYeniden başlamak için ekrana dokunun."; mood = "angry"; crossX = true; } else if (endingType === "lust") { // Lisa uzaklaşıyor portraitKey = "lisa"; endingText = "SON: Lisa, Mike'ın tutkularının sönmesiyle uzaklaştı.\n\nYeniden başlamak için ekrana dokunun."; mood = "sad"; crossX = true; } else if (endingType === "happy") { // Mike depresyona giriyor portraitKey = "mike"; endingText = "SON: Mike mutluluğunu kaybetti ve depresyona girdi.\n\nYeniden başlamak için ekrana dokunun."; mood = "sad"; crossX = false; } else if (endingType === "honest") { // Mike yalanlarla dolu bir hayata saplandı portraitKey = "mike"; endingText = "SON: Mike dürüstlüğünü kaybetti, yalanlarla dolu bir hayata saplandı.\n\nYeniden başlamak için ekrana dokunun."; mood = "angry"; crossX = true; } // Show ending text if (storyText) { if (endingText) { storyText.setText(endingText); } else if (msg) { storyText.setText('SON: ' + msg + '\n\nYeniden başlamak için ekrana dokunun.'); } else { storyText.setText('SON: Mike’ın hikayesi burada bitiyor.\n\nYeniden başlamak için ekrana dokunun.'); } } // Remove speaker if (speakerText) speakerText.setText(''); // Animate portrait: change to relevant character, mood tint, fade out, and cross if needed if (portraitNode) { // Change portrait image if (LK.getAsset(portraitKey, {})) { portraitNode.texture = LK.getAsset(portraitKey, {}).texture; } // Mood-based tint var moodTints = { happy: 0x7ed321, sad: 0x4a90e2, angry: 0xd0021b, neutral: 0xffffff }; var tint = moodTints[mood] !== undefined ? moodTints[mood] : 0xffffff; portraitNode.tint = tint; // Animate: fade out after 1.2s tween(portraitNode, { alpha: 0.3 }, { duration: 1200, easing: tween.easeOut }); // If crossX, show a red cross over portrait if (crossX) { // Create a red cross using two rectangles (since we can't draw lines) var cross1 = LK.getAsset('bar_fill_betray', { anchorX: 0.5, anchorY: 0.5 }); var cross2 = LK.getAsset('bar_fill_betray', { anchorX: 0.5, anchorY: 0.5 }); // Set size and rotation for cross var size = Math.max(portraitNode.width, portraitNode.height) * 0.9; cross1.width = size; cross1.height = 24; cross2.width = size; cross2.height = 24; cross1.rotation = Math.PI / 4; cross2.rotation = -Math.PI / 4; cross1.alpha = 0.85; cross2.alpha = 0.85; cross1.x = portraitNode.x; cross1.y = portraitNode.y; cross2.x = portraitNode.x; cross2.y = portraitNode.y; cross1.zIndex = 100; cross2.zIndex = 100; game.addChild(cross1); game.addChild(cross2); // Animate cross: fade in, then fade out after 1.2s cross1.alpha = 0; cross2.alpha = 0; tween(cross1, { alpha: 0.85 }, { duration: 400, easing: tween.easeOut }); tween(cross2, { alpha: 0.85 }, { duration: 400, easing: tween.easeOut }); // Fade out after 1.2s LK.setTimeout(function () { tween(cross1, { alpha: 0 }, { duration: 600, easing: tween.easeOut }); tween(cross2, { alpha: 0 }, { duration: 600, easing: tween.easeOut }); LK.setTimeout(function () { game.removeChild(cross1); game.removeChild(cross2); }, 700); }, 1200); } } // Add restart handler game.down = function (x, y, obj) { game.down = null; restartGame(); }; } function restartGame() { resetGameState(); updateBars(); showStoryNode(currentNode); // Remove restart handler game.down = null; } // --- Start Game --- resetGameState(); createUI(); updateBars(); showStoryNode(currentNode); // --- No dragging or move events needed for this game --- // --- Game update (not used, but required for LK) --- game.update = function () { // No per-frame logic needed };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// OptionButton: For displaying a choice
var OptionButton = Container.expand(function () {
var self = Container.call(this);
self.bg = self.attachAsset('option_btn', {
anchorX: 0.5,
anchorY: 0.5
});
self.text = null;
self.callback = null;
self.setText = function (str) {
if (self.text) self.removeChild(self.text);
self.text = new Text2(str, {
size: 54,
fill: '#222222'
});
self.text.anchor.set(0.5, 0.5);
self.text.x = 0;
self.text.y = 0;
self.addChild(self.text);
};
self.setCallback = function (cb) {
self.callback = cb;
};
self.down = function (x, y, obj) {
if (self.callback) self.callback();
};
return self;
});
// Passive background object base class
var PassiveBgObject = Container.expand(function () {
var self = Container.call(this);
self.speed = 0;
self.assetId = '';
self.asset = null;
self.setAsset = function (assetId) {
if (self.asset) self.removeChild(self.asset);
self.assetId = assetId;
self.asset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.resetPosition = function () {
// Start just outside right edge, random Y
self.x = 2048 + (self.asset ? self.asset.width : 100) / 2 + Math.random() * 200;
self.y = 200 + Math.random() * 2100;
};
self.update = function () {
if (typeof self.lastX === "undefined") self.lastX = self.x;
self.x -= self.speed;
// If off screen to the left, reset
if (self.lastX >= -200 && self.x < -200) {
self.resetPosition();
}
self.lastX = self.x;
};
return self;
});
// Motorcycle
var BgMotorcycle = PassiveBgObject.expand(function () {
var self = PassiveBgObject.call(this);
self.setAsset('bg_motorcycle');
self.speed = 4.0 + Math.random() * 1.5;
self.resetPosition();
return self;
});
// Heart
var BgHeart = PassiveBgObject.expand(function () {
var self = PassiveBgObject.call(this);
self.setAsset('bg_heart');
self.speed = 2.7 + Math.random() * 1.2;
self.resetPosition();
return self;
});
// Football
var BgFootball = PassiveBgObject.expand(function () {
var self = PassiveBgObject.call(this);
self.setAsset('bg_football');
self.speed = 2.5 + Math.random() * 1.2;
self.resetPosition();
return self;
});
// Car
var BgCar = PassiveBgObject.expand(function () {
var self = PassiveBgObject.call(this);
self.setAsset('bg_car');
self.speed = 3.2 + Math.random() * 1.5;
self.resetPosition();
return self;
});
// Briefcase
var BgBriefcase = PassiveBgObject.expand(function () {
var self = PassiveBgObject.call(this);
self.setAsset('bg_briefcase');
self.speed = 2.2 + Math.random() * 1.2;
self.resetPosition();
return self;
});
// RelationshipBar: For displaying and updating a bar (happiness, honesty, lust, betrayal)
var RelationshipBar = Container.expand(function () {
var self = Container.call(this);
self.bg = self.attachAsset('bar_bg', {
anchorX: 0,
anchorY: 0
});
self.fill = null;
self.label = null;
self.value = 100; // 0-100
self.maxWidth = 400;
self.type = 'happy'; // 'happy', 'honest', 'lust', 'betray'
self.setType = function (type) {
self.type = type;
var fillId = 'bar_fill_happy';
if (type === 'honest') fillId = 'bar_fill_honest';
if (type === 'lust') fillId = 'bar_fill_lust';
if (type === 'betray') fillId = 'bar_fill_betray';
if (self.fill) self.removeChild(self.fill);
self.fill = self.attachAsset(fillId, {
anchorX: 0,
anchorY: 0
});
self.fill.x = 0;
self.fill.y = 0;
self.fill.width = self.maxWidth;
self.fill.height = 40;
self.fill.zIndex = 1;
self.bg.zIndex = 0;
self.setValue(self.value);
};
self.setValue = function (val) {
self.value = Math.max(0, Math.min(100, val));
if (self.fill) {
self.fill.width = self.maxWidth * (self.value / 100);
}
if (self.label) {
self.label.setText(self.value + '%');
}
};
self.setLabel = function (text) {
if (self.label) self.removeChild(self.label);
self.label = new Text2(text, {
size: 36,
fill: '#ffffff'
});
self.label.anchor.set(1, 0.5);
self.label.x = self.maxWidth + 20;
self.label.y = 20;
self.addChild(self.label);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Animate passive background objects
// Sağdan sola giden araba
// Sağdan sola giden iş çantası
// Sağdan sola giden ateşli kalp
// Sağdan sola giden futbol topu
// Sağdan sola giden motor
// --- Shop/Store assets (right side) ---
// Example id, replace with real
if (typeof bgObjects !== "undefined") {
for (var i = 0; i < bgObjects.length; i++) {
if (bgObjects[i] && typeof bgObjects[i].update === "function") {
bgObjects[i].update();
}
}
}
// No per-frame logic needed
// Not: 'background' asseti image olarak tanımlanmalı, ör: LK.init.image('background', {width:2048, height:2732, id:'YOUR_IMAGE_ID'})
var backgroundNode = LK.getAsset('background', {
anchorX: 0,
anchorY: 0
});
backgroundNode.width = 2048;
backgroundNode.height = 2732;
backgroundNode.x = 0;
backgroundNode.y = 0;
backgroundNode.zIndex = -100; // Her şeyin arkasında dursun
game.addChild(backgroundNode);
// --- Passive background objects (car, briefcase, heart, football, motorcycle) ---
var bgObjects = [];
function spawnBgObjects() {
// Remove old ones if any
for (var i = 0; i < bgObjects.length; i++) {
if (bgObjects[i] && bgObjects[i].parent) {
game.removeChild(bgObjects[i]);
}
}
bgObjects = [];
// Add 2 of each for variety
for (var i = 0; i < 2; i++) {
var car = new BgCar();
var briefcase = new BgBriefcase();
var heart = new BgHeart();
var football = new BgFootball();
var motorcycle = new BgMotorcycle();
game.addChild(car);
game.addChild(briefcase);
game.addChild(heart);
game.addChild(football);
game.addChild(motorcycle);
bgObjects.push(car, briefcase, heart, football, motorcycle);
}
}
spawnBgObjects();
// Çarpıcı seçimler: her 4-6 sahnede bir, yüksek risk/ödül, animasyonlu, barları büyük oranda etkiler
// --- Dramatic Choice (Çarpıcı Seçim) System ---
var dramaticChoices = [{
id: "rebecca_room",
text: "Rebecca ile iş gezisindesiniz. Aynı odada mı kalacaksınız, farklı mı?",
portrait: "rebecca",
speaker: "Rebecca",
dramatic: true,
options: [{
text: "Aynı odada kal",
effects: {
rebecca: 15,
lust: 15,
betray: 15
},
meta: {
memoryLabel: "rebecca_room_same"
}
}, {
text: "Farklı odada kal",
effects: {
honest: 10,
rebecca: -5
},
meta: {
memoryLabel: "rebecca_room_diff"
}
}]
}, {
id: "lisa_warns_alex",
text: "Lisa seni, iş yerinde Alex ile fazla yakın görünmen konusunda uyarıyor. Tepkin ne olur?",
portrait: "lisa",
speaker: "Lisa",
dramatic: true,
options: [{
text: "Anlar ve saygı gösterirsin",
effects: {
lisa: 20,
honest: 15
},
meta: {
memoryLabel: "lisa_warns_respect"
}
}, {
text: "Umursamaz davranırsın",
effects: {
lisa: -20,
betray: 15
},
meta: {
memoryLabel: "lisa_warns_ignore"
}
}]
}, {
id: "alex_secret",
text: "Alex senden gizli bir bilgi istiyor. Paylaşacak mısın?",
portrait: "alex",
speaker: "Alex",
dramatic: true,
options: [{
text: "Paylaş",
effects: {
betray: 20,
alex: 10
},
meta: {
memoryLabel: "alex_secret_share"
}
}, {
text: "Sakla",
effects: {
honest: 20,
alex: -10
},
meta: {
memoryLabel: "alex_secret_hide"
}
}]
}, {
id: "peter_lisa_fears",
text: "Peter sana, Lisa ile ilgili endişelerini paylaşıyor. Ona inanacak mısın?",
portrait: "peter",
speaker: "Peter",
dramatic: true,
options: [{
text: "Evet",
effects: {
peter: 15,
honest: 10
},
meta: {
memoryLabel: "peter_lisa_believe"
}
}, {
text: "Hayır",
effects: {
peter: -15,
betray: 10
},
meta: {
memoryLabel: "peter_lisa_deny"
}
}]
}, {
id: "rebecca_night",
text: "Rebecca gece seni evine davet ediyor. Gidiyor musun?",
portrait: "rebecca",
speaker: "Rebecca",
dramatic: true,
options: [{
text: "Evet",
effects: {
rebecca: 20,
lust: 15,
betray: 20
},
meta: {
memoryLabel: "rebecca_night_yes"
}
}, {
text: "Hayır",
effects: {
honest: 15
},
meta: {
memoryLabel: "rebecca_night_no"
}
}]
}, {
id: "lisa_serious_talk",
text: "Lisa, seninle ciddi bir konuşma yapmak istiyor. Onu dinleyecek misin?",
portrait: "lisa",
speaker: "Lisa",
dramatic: true,
options: [{
text: "Dinle",
effects: {
lisa: 20,
honest: 10
},
meta: {
memoryLabel: "lisa_serious_listen"
}
}, {
text: "Dinleme",
effects: {
lisa: -20,
happy: -15
},
meta: {
memoryLabel: "lisa_serious_ignore"
}
}]
}, {
id: "alex_secret_deal",
text: "Alex ile gizli bir anlaşma teklif ediyor. Kabul edecek misin?",
portrait: "alex",
speaker: "Alex",
dramatic: true,
options: [{
text: "Evet",
effects: {
alex: 20,
betray: 20
},
meta: {
memoryLabel: "alex_deal_yes"
}
}, {
text: "Hayır",
effects: {
honest: 20,
alex: -15
},
meta: {
memoryLabel: "alex_deal_no"
}
}]
}, {
id: "peter_big_secret",
text: "Peter, seni büyük bir sırrı hakkında uyarıyor. Güveniyor musun?",
portrait: "peter",
speaker: "Peter",
dramatic: true,
options: [{
text: "Evet",
effects: {
peter: 20,
honest: 10
},
meta: {
memoryLabel: "peter_secret_trust"
}
}, {
text: "Hayır",
effects: {
peter: -20,
betray: 15
},
meta: {
memoryLabel: "peter_secret_distrust"
}
}]
}, {
id: "rebecca_club",
text: "Rebecca ile bir gece kulübünde dans ediyorsun. Daha yakın davranacak mısın?",
portrait: "rebecca",
speaker: "Rebecca",
dramatic: true,
options: [{
text: "Evet",
effects: {
rebecca: 15,
lust: 15,
betray: 10
},
meta: {
memoryLabel: "rebecca_club_yes"
}
}, {
text: "Hayır",
effects: {
honest: 10
},
meta: {
memoryLabel: "rebecca_club_no"
}
}]
}, {
id: "lisa_gossip",
text: "Lisa seni iş arkadaşlarınla ilgili dedikodulara karışmakla suçluyor. Savunacak mısın?",
portrait: "lisa",
speaker: "Lisa",
dramatic: true,
options: [{
text: "Savun",
effects: {
lisa: 10,
honest: 15
},
meta: {
memoryLabel: "lisa_gossip_defend"
}
}, {
text: "Kabullen",
effects: {
lisa: -15,
betray: 10
},
meta: {
memoryLabel: "lisa_gossip_admit"
}
}]
}, {
id: "alex_promotion",
text: "Alex, seni iş yerinde terfi ile ödüllendiriyor ama bir karşılık bekliyor. Kabul edecek misin?",
portrait: "alex",
speaker: "Alex",
dramatic: true,
options: [{
text: "Evet",
effects: {
alex: 25,
betray: 25
},
meta: {
memoryLabel: "alex_promotion_yes"
}
}, {
text: "Hayır",
effects: {
honest: 20
},
meta: {
memoryLabel: "alex_promotion_no"
}
}]
}, {
id: "peter_sacrifice",
text: "Peter’in sana yardım etmek için büyük bir fedakarlık yapması gerekiyor. Kabul edecek misin?",
portrait: "peter",
speaker: "Peter",
dramatic: true,
options: [{
text: "Evet",
effects: {
peter: 25,
happy: 15
},
meta: {
memoryLabel: "peter_sacrifice_yes"
}
}, {
text: "Hayır",
effects: {
peter: -20,
betray: 10
},
meta: {
memoryLabel: "peter_sacrifice_no"
}
}]
}, {
id: "rebecca_restaurant",
text: "Rebecca, iş seyahatinde seni bir restoranda yalnız bırakıyor. Tek başına kalacak mısın yoksa kalabalığa mı karışacaksın?",
portrait: "rebecca",
speaker: "Rebecca",
dramatic: true,
options: [{
text: "Tek başına",
effects: {
rebecca: 10,
lust: 10
},
meta: {
memoryLabel: "rebecca_restaurant_alone"
}
}, {
text: "Kalabalık",
effects: {
honest: 10
},
meta: {
memoryLabel: "rebecca_restaurant_crowd"
}
}]
}, {
id: "lisa_memory",
text: "Lisa sana eski bir anısını anlatıyor ve senden destek bekliyor. Onun yanında olacak mısın?",
portrait: "lisa",
speaker: "Lisa",
dramatic: true,
options: [{
text: "Evet",
effects: {
lisa: 20,
happy: 15
},
meta: {
memoryLabel: "lisa_memory_yes"
}
}, {
text: "Hayır",
effects: {
lisa: -15
},
meta: {
memoryLabel: "lisa_memory_no"
}
}]
}, {
id: "alex_ethics",
text: "Alex’in zorlayıcı teklifine karşılık verirken etik dışı bir şey yapman isteniyor. Kabul mü?",
portrait: "alex",
speaker: "Alex",
dramatic: true,
options: [{
text: "Evet",
effects: {
alex: 20,
betray: 25
},
meta: {
memoryLabel: "alex_ethics_yes"
}
}, {
text: "Hayır",
effects: {
honest: 20
},
meta: {
memoryLabel: "alex_ethics_no"
}
}]
}, {
id: "peter_secret_share",
text: "Peter seni beklenmedik bir şekilde büyük bir sırrını açıklıyor. Tepkin ne olur?",
portrait: "peter",
speaker: "Peter",
dramatic: true,
options: [{
text: "Sırlarınızı paylaşmaya devam edersin",
effects: {
peter: 20,
honest: 15
},
meta: {
memoryLabel: "peter_secret_share_yes"
}
}, {
text: "Mesafeli olursun",
effects: {
peter: -15,
betray: 10
},
meta: {
memoryLabel: "peter_secret_share_no"
}
}]
}, {
id: "rebecca_bar_lisa",
text: "Rebecca ile iş sonrası bara gittiniz. Lisa ile yüzleşmeye hazır mısın?",
portrait: "rebecca",
speaker: "Rebecca",
dramatic: true,
options: [{
text: "Evet",
effects: {
betray: 20,
lust: 15,
rebecca: 10
},
meta: {
memoryLabel: "rebecca_bar_lisa_yes"
}
}, {
text: "Hayır",
effects: {
honest: 15,
lisa: 10
},
meta: {
memoryLabel: "rebecca_bar_lisa_no"
}
}]
}, {
id: "lisa_crisis",
text: "Lisa sana, evlilikte bir kriz yaşıyor ve profesyonel yardım almak istiyor. Destek verir misin?",
portrait: "lisa",
speaker: "Lisa",
dramatic: true,
options: [{
text: "Evet",
effects: {
lisa: 25,
happy: 20
},
meta: {
memoryLabel: "lisa_crisis_yes"
}
}, {
text: "Hayır",
effects: {
lisa: -25
},
meta: {
memoryLabel: "lisa_crisis_no"
}
}]
}, {
id: "alex_risk",
text: "Alex, kariyerin için büyük bir tehlike barındıran bir riski göze almana izin veriyor. Kabul mü?",
portrait: "alex",
speaker: "Alex",
dramatic: true,
options: [{
text: "Evet",
effects: {
alex: 30,
betray: 30
},
meta: {
memoryLabel: "alex_risk_yes"
}
}, {
text: "Hayır",
effects: {
honest: 20
},
meta: {
memoryLabel: "alex_risk_no"
}
}]
}, {
id: "peter_conflict",
text: "Peter ile aranızda aniden büyük bir anlaşmazlık çıkıyor. Özür dileyecek misin?",
portrait: "peter",
speaker: "Peter",
dramatic: true,
options: [{
text: "Evet",
effects: {
peter: 20,
happy: 15
},
meta: {
memoryLabel: "peter_conflict_yes"
}
}, {
text: "Hayır",
effects: {
peter: -20,
betray: 15
},
meta: {
memoryLabel: "peter_conflict_no"
}
}]
}];
// Dramatic choice frequency: every 4-6 turns, randomize
var nextDramaticTurn = 4 + Math.floor(Math.random() * 3);
var dramaticHistory = [];
// Helper: get a random dramatic choice not recently shown
function getDramaticChoice() {
var available = [];
for (var i = 0; i < dramaticChoices.length; i++) {
if (dramaticHistory.indexOf(dramaticChoices[i].id) === -1) {
available.push(dramaticChoices[i]);
}
}
// If all have been shown, reset history
if (available.length === 0) {
dramaticHistory = [];
available = dramaticChoices.slice();
}
var idx = Math.floor(Math.random() * available.length);
return available[idx];
}
// Show a dramatic choice with animation, music pause, and shadow overlay
function showDramaticChoice() {
// Remove old option buttons
for (var i = 0; i < optionButtons.length; i++) {
game.removeChild(optionButtons[i]);
}
optionButtons = [];
// Pick a dramatic choice
var node = getDramaticChoice();
dramaticHistory.push(node.id);
// Pause music (if any)
if (typeof LK.stopMusic === "function") LK.stopMusic();
// Shadow overlay
if (!game._dramaticShadow) {
var shadow = LK.getAsset('bar_bg', {
anchorX: 0,
anchorY: 0
});
shadow.width = 2048;
shadow.height = 2732;
shadow.x = 0;
shadow.y = 0;
shadow.alpha = 0.0; // Start fully transparent
shadow.zIndex = 99;
game.addChild(shadow);
game._dramaticShadow = shadow;
// Animate shadow fade-in
tween(shadow, {
alpha: 0.7
}, {
duration: 220,
easing: tween.easeOut
});
} else {
// If already present, ensure it's visible and interactive
game._dramaticShadow.alpha = 0.7;
game._dramaticShadow.zIndex = 99;
}
// Portrait
if (portraitNode && node.portrait && LK.getAsset(node.portrait, {})) {
portraitNode.texture = LK.getAsset(node.portrait, {}).texture;
portraitNode.tint = 0xffffff;
}
// Speaker
if (speakerText) speakerText.setText(node.speaker ? node.speaker : '');
// Story text
if (storyText) {
storyText.setText(node.text);
storyText.alpha = 1.0; // No animation
}
// Dramatic option buttons: ensure visible, enabled, and selectable
for (var i = 0; i < node.options.length; i++) {
(function (opt, idx) {
var btn = new OptionButton();
btn.setText(opt.text);
// Büyük ve dikkat çekici: butonları daha büyük yap
btn.scale.x = 1.35;
btn.scale.y = 1.35;
// Ekranda tamamen görünür ve aralıklı olacak şekilde ayarla
// Yüksekliğe göre ortala, iki seçenek için yukarıdan ve aşağıdan eşit boşluk bırak
var totalBtnHeight = 2 * (btn.bg.height * btn.scale.y) + 120;
var startY = 1800 - totalBtnHeight / 2;
btn.x = 2048 / 2;
btn.y = startY + idx * (btn.bg.height * btn.scale.y + 120);
btn.alpha = 1.0;
btn.bg.tint = 0x000000;
if (btn.text && btn.text.style) btn.text.style.fill = '#ffffff';
btn.zIndex = 100;
btn.interactive = true;
btn.buttonMode = true;
// Make sure button is enabled and not grayed out
btn.bg.tint = 0x000000;
if (btn.text && btn.text.style) btn.text.style.fill = '#ffffff';
// Remove any previous disabled state
btn.alpha = 1.0;
btn.visible = true;
btn.setCallback(function () {
// Seçim sırasında iki butonu da büyüt ve animasyon ekle
for (var j = 0; j < optionButtons.length; j++) {
var b = optionButtons[j];
// Seçilen buton daha fazla büyüsün, diğeri de büyüsün ama biraz az
var targetScale = b === btn ? 1.55 : 1.25;
tween(b.scale, {
x: targetScale,
y: targetScale
}, {
duration: 220,
easing: tween.easeOut
});
tween(b, {
alpha: 1
}, {
duration: 220,
easing: tween.easeOut
});
}
// Seçimden kısa süre sonra butonları ve gölgeyi kaldır
LK.setTimeout(function () {
// Remove shadow overlay with fade out
if (game._dramaticShadow) {
tween(game._dramaticShadow, {
alpha: 0
}, {
duration: 180,
easing: tween.easeIn,
onFinish: function onFinish() {
if (game._dramaticShadow) {
game.removeChild(game._dramaticShadow);
game._dramaticShadow = null;
}
}
});
}
// Remove buttons instantly
for (var j = 0; j < optionButtons.length; j++) {
(function (b) {
game.removeChild(b);
})(optionButtons[j]);
}
optionButtons = [];
// Apply effects (dramatic: +10~+30 or -30)
applyDramaticEffects(opt.effects, opt.meta);
// Resume music (if any)
if (typeof LK.playMusic === "function") LK.playMusic('musicId');
// Next dramatic turn: 4-6 turns later
nextDramaticTurn = turnCount + 4 + Math.floor(Math.random() * 3);
// Continue with normal story
LK.setTimeout(function () {
var nextIdx = getNextNode();
currentNode = nextIdx;
showStoryNode(currentNode);
}, 600);
}, 260);
});
game.addChild(btn);
optionButtons.push(btn);
})(node.options[i], i);
}
}
// Apply dramatic effects: bar changes are much larger
function applyDramaticEffects(effects, meta) {
if (!effects) return;
// Record memory
if (meta && meta.memoryLabel) pastChoices.push(meta.memoryLabel);
// Dramatic: apply full effect value (not just +1/-1)
if (typeof effects.lisa === 'number') rel_lisa = Math.max(0, Math.min(100, rel_lisa + effects.lisa));
if (typeof effects.rebecca === 'number') rel_rebecca = Math.max(0, Math.min(100, rel_rebecca + effects.rebecca));
if (typeof effects.peter === 'number') rel_peter = Math.max(0, Math.min(100, rel_peter + effects.peter));
if (typeof effects.alex === 'number') rel_alex = Math.max(0, Math.min(100, rel_alex + effects.alex));
if (typeof effects.happy === 'number') bar_happy = Math.max(0, Math.min(100, bar_happy + effects.happy));
if (typeof effects.honest === 'number') bar_honest = Math.max(0, Math.min(100, bar_honest + effects.honest));
if (typeof effects.lust === 'number') bar_lust = Math.max(0, Math.min(100, bar_lust + effects.lust));
if (typeof effects.betray === 'number') bar_betray = Math.max(0, Math.min(100, bar_betray + effects.betray));
// Shadow bar: dramatic choices have bigger impact
if (typeof effects.betray === 'number' && effects.betray > 0) bar_shadow = Math.max(0, Math.min(100, bar_shadow + 10));
if (typeof effects.honest === 'number' && effects.honest > 0) bar_shadow = Math.max(0, bar_shadow - 5);
updateBars();
turnCount++;
// Cross effects
applyCrossEffects(effects, meta);
// Check for ending
if (bar_happy <= 0) {
showEnding('Mutluluk sıfırlandı. Mike depresyona girdi.');
return;
}
if (bar_honest <= 0) {
showEnding('Dürüstlük sıfırlandı. Mike yalanlarla dolu bir hayata saplandı.');
return;
}
if (bar_lust <= 0) {
showEnding('Şehvet sıfırlandı. Mike hayattan keyif alamıyor.');
return;
}
if (bar_betray >= 100) {
showEnding('İhanet %100 oldu. Mike ilişkilerini kaybetti.');
return;
}
}
// Each story node: { text, options: [ {text, effects, next} ], portrait, speaker }
// --- Story Data ---
// Character portraits (simple colored boxes for now)
// Bar backgrounds and fills
// Option buttons
// --- Whiskey'e özel sorular (yalnızca satın alındıysa gösterilecek) ---
var whiskeyQuestions = [{
id: "whiskey_intro",
text: "Whiskey: 'Hav hav! Mike, parka gidelim mi?'",
portrait: "whiskey",
speaker: "Whiskey",
options: [{
text: "Whiskey'i parka götür.",
effects: {
happy: 5
}
}, {
text: "Bugün evde kalalım.",
effects: {
happy: -2
}
}]
}, {
id: "whiskey_walk",
text: "Whiskey kapının önünde heyecanla bekliyor. Dışarı çıkarmak ister misin?",
portrait: "whiskey",
speaker: "Whiskey",
options: [{
text: "Whiskey ile uzun yürüyüş yap.",
effects: {
happy: 5
}
}, {
text: "Kısa bir yürüyüş yap.",
effects: {
happy: 2
}
}, {
text: "Yürüyüşe çıkma.",
effects: {
happy: -3
}
}]
}, {
id: "whiskey_vet",
text: "Whiskey biraz halsiz görünüyor. Veterinere götürecek misin?",
portrait: "whiskey",
speaker: "Whiskey",
options: [{
text: "Veterinere götür. ($200 harca)",
effects: {
happy: 5
},
meta: {
type: "whiskey_spend",
money: -200
}
}, {
text: "Evde dinlensin.",
effects: {
happy: -2
}
}]
}, {
id: "whiskey_toy",
text: "Whiskey yeni bir oyuncak istiyor.",
portrait: "whiskey",
speaker: "Whiskey",
options: [{
text: "Oyuncak al. ($50 harca)",
effects: {
happy: 3
},
meta: {
type: "whiskey_spend",
money: -50
}
}, {
text: "Oyuncak alma.",
effects: {
happy: -2
}
}]
}, {
id: "whiskey_bath",
text: "Whiskey çamura bulandı! Yıkayacak mısın?",
portrait: "whiskey",
speaker: "Whiskey",
options: [{
text: "Whiskey'i yıka.",
effects: {
happy: 2
}
}, {
text: "Yıkamadan bırak.",
effects: {
happy: -3
}
}]
}, {
id: "whiskey_trick",
text: "Whiskey yeni bir numara öğrenmek istiyor. Öğretecek misin?",
portrait: "whiskey",
speaker: "Whiskey",
options: [{
text: "Yeni numara öğret.",
effects: {
happy: 4
}
}, {
text: "Vakit ayırma.",
effects: {
happy: -2
}
}]
}, {
id: "whiskey_vacation",
text: "Tatile çıkacaksınız. Whiskey'i de götürecek misin?",
portrait: "whiskey",
speaker: "Whiskey",
options: [{
text: "Whiskey'i de götür. ($300 harca)",
effects: {
happy: 5
},
meta: {
type: "whiskey_spend",
money: -300
}
}, {
text: "Whiskey'i pansiyona bırak. ($150 harca)",
effects: {
happy: 2
},
meta: {
type: "whiskey_spend",
money: -150
}
}]
}, {
id: "whiskey_birthday",
text: "Whiskey'in doğum günü! Ona özel bir şey yapmak ister misin?",
portrait: "whiskey",
speaker: "Whiskey",
options: [{
text: "Köpek pastası al. ($80 harca)",
effects: {
happy: 4
},
meta: {
type: "whiskey_spend",
money: -80
}
}, {
text: "Sadece sarıl.",
effects: {
happy: 2
}
}]
}, {
id: "whiskey_lost",
text: "Whiskey bahçede kayboldu! Arayacak mısın?",
portrait: "whiskey",
speaker: "Whiskey",
options: [{
text: "Bahçede ara.",
effects: {
happy: 3
}
}, {
text: "Kendi gelir diye bekle.",
effects: {
happy: -3
}
}]
}, {
id: "whiskey_vet2",
text: "Whiskey aşı zamanı geldi. Aşı yaptıracak mısın?",
portrait: "whiskey",
speaker: "Whiskey",
options: [{
text: "Aşı yaptır. ($120 harca)",
effects: {
happy: 3
},
meta: {
type: "whiskey_spend",
money: -120
}
}, {
text: "Aşıyı ertele.",
effects: {
happy: -2
}
}]
}];
// --- Villa'ya davet eventleri ve özel sorular (her karakter için 2'şer tane) ---
var villaInviteEvents = [{
id: "villa_invite_lisa",
text: "Artık bir villan var! Lisa'yı eve davet etmek ister misin?",
portrait: "lisa",
speaker: "Lisa",
options: [{
text: "Lisa'yı villaya davet et.",
effects: {
lisa: 15,
happy: 5
},
meta: {
type: "villa_invite",
character: "lisa"
}
}, {
text: "Davet etme.",
effects: {
lisa: -2
}
}]
}, {
id: "villa_invite_rebecca",
text: "Artık bir villan var! Rebecca'yı eve davet etmek ister misin?",
portrait: "rebecca",
speaker: "Rebecca",
options: [{
text: "Rebecca'yı villaya davet et.",
effects: {
rebecca: 15,
happy: 5
},
meta: {
type: "villa_invite",
character: "rebecca"
}
}, {
text: "Davet etme.",
effects: {
rebecca: -2
}
}]
}, {
id: "villa_invite_peter",
text: "Artık bir villan var! Peter'ı eve davet etmek ister misin?",
portrait: "peter",
speaker: "Peter",
options: [{
text: "Peter'ı villaya davet et.",
effects: {
peter: 15,
happy: 5
},
meta: {
type: "villa_invite",
character: "peter"
}
}, {
text: "Davet etme.",
effects: {
peter: -2
}
}]
}, {
id: "villa_invite_alex",
text: "Artık bir villan var! Alex'i eve davet etmek ister misin?",
portrait: "alex",
speaker: "Alex",
options: [{
text: "Alex'i villaya davet et.",
effects: {
alex: 15,
happy: 5
},
meta: {
type: "villa_invite",
character: "alex"
}
}, {
text: "Davet etme.",
effects: {
alex: -2
}
}]
}];
var villaSpecialQuestions = [
// Lisa
{
id: "villa_lisa_1",
text: "Lisa: 'Bu evde birlikte yeni anılar biriktirelim mi?'",
portrait: "lisa",
speaker: "Lisa",
options: [{
text: "Evet, birlikte çok güzel anılarımız olacak.",
effects: {
lisa: 10,
happy: 5
}
}, {
text: "Ev güzel ama önemli olan sensin.",
effects: {
lisa: 7,
honest: 3
}
}]
}, {
id: "villa_lisa_2",
text: "Lisa: 'Villada bir parti verelim mi?'",
portrait: "lisa",
speaker: "Lisa",
options: [{
text: "Harika fikir, parti verelim.",
effects: {
lisa: 8,
happy: 4
}
}, {
text: "Parti istemiyorum.",
effects: {
lisa: -3
}
}]
},
// Rebecca
{
id: "villa_rebecca_1",
text: "Rebecca: 'Villanın havuzunda gece yüzmek ister misin?'",
portrait: "rebecca",
speaker: "Rebecca",
options: [{
text: "Tabii, birlikte yüzmek harika olur.",
effects: {
rebecca: 10,
lust: 5
}
}, {
text: "Yorgunum, başka zaman.",
effects: {
rebecca: -2
}
}]
}, {
id: "villa_rebecca_2",
text: "Rebecca: 'Villada baş başa bir akşam geçirelim mi?'",
portrait: "rebecca",
speaker: "Rebecca",
options: [{
text: "Evet, baş başa kalmak güzel olur.",
effects: {
rebecca: 8,
happy: 3
}
}, {
text: "Bugün olmaz.",
effects: {
rebecca: -2
}
}]
},
// Peter
{
id: "villa_peter_1",
text: "Peter: 'Bahçede mangal yapalım mı?'",
portrait: "peter",
speaker: "Peter",
options: [{
text: "Mangal harika olur!",
effects: {
peter: 10,
happy: 4
}
}, {
text: "Başka zaman.",
effects: {
peter: -2
}
}]
}, {
id: "villa_peter_2",
text: "Peter: 'Villada birlikte film gecesi yapalım mı?'",
portrait: "peter",
speaker: "Peter",
options: [{
text: "Evet, film gecesi yapalım.",
effects: {
peter: 8,
happy: 3
}
}, {
text: "İstemiyorum.",
effects: {
peter: -2
}
}]
},
// Alex
{
id: "villa_alex_1",
text: "Alex: 'Bu villada iş toplantısı yapmak isterim.'",
portrait: "alex",
speaker: "Alex",
options: [{
text: "Tabii, toplantı yapabiliriz.",
effects: {
alex: 10,
happy: 2
}
}, {
text: "Evde iş konuşmak istemiyorum.",
effects: {
alex: -2
}
}]
}, {
id: "villa_alex_2",
text: "Alex: 'Villanın manzarası harika, burada çalışmak isterim.'",
portrait: "alex",
speaker: "Alex",
options: [{
text: "İstediğin zaman gelebilirsin.",
effects: {
alex: 8,
honest: 2
}
}, {
text: "Evde yalnız kalmak istiyorum.",
effects: {
alex: -2
}
}]
}];
// --- Giselle'e özel sorular (yalnızca satın alındıysa gösterilecek) ---
var giselleQuestions = [{
id: "giselle_intro",
text: "Giselle: 'Mike, yeni bir çanta almak istiyorum. Bütçemiz yeterli mi?'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Tabii, hemen alalım. ($500 harca)",
effects: {
happy: 5
},
meta: {
type: "giselle_spend",
money: -500
}
}, {
text: "Şu an alamayız, bütçemiz kısıtlı.",
effects: {
happy: -5,
honest: 5
},
meta: {
type: "truth"
}
}]
}, {
id: "giselle_shopping",
text: "Giselle: 'Alışverişe çıkalım mı? Birkaç şey almak istiyorum.'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Giselle'e para ver. ($300 harca)",
effects: {
happy: 5
},
meta: {
type: "giselle_spend",
money: -300
}
}, {
text: "Bugün alışveriş yok.",
effects: {
happy: -5
}
}]
}, {
id: "giselle_dinner",
text: "Giselle: 'Bu akşam dışarıda yemek yiyelim mi?'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Lüks restorana git. ($400 harca)",
effects: {
happy: 10,
lust: 5
},
meta: {
type: "giselle_spend",
money: -400
}
}, {
text: "Evde yemek yapalım.",
effects: {
happy: -5
}
}]
}, {
id: "giselle_gift",
text: "Giselle: 'Bana hediye alır mısın?'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Pahalı bir kolye al. ($1000 harca)",
effects: {
happy: 10,
lust: 5
},
meta: {
type: "giselle_spend",
money: -1000
}
}, {
text: "Küçük bir hediye al. ($100 harca)",
effects: {
happy: 3
},
meta: {
type: "giselle_spend",
money: -100
}
}, {
text: "Hediye almayacağım.",
effects: {
happy: -10
}
}]
}, {
id: "giselle_jealous",
text: "Giselle: 'Lisa ile çok vakit geçiriyorsun, kıskanıyorum.'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Giselle'e güven ver.",
effects: {
happy: 5,
honest: 5
}
}, {
text: "Lisa ile görüşmeyi azalt.",
effects: {
happy: 2,
lust: -2
}
}]
}, {
id: "giselle_party",
text: "Giselle: 'Hafta sonu partiye gidelim mi?'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Partiye git. ($200 harca)",
effects: {
happy: 5,
lust: 5
},
meta: {
type: "giselle_spend",
money: -200
}
}, {
text: "Evde kalalım.",
effects: {
happy: -3
}
}]
}, {
id: "giselle_baby",
text: "Giselle: 'Bir bebek sahibi olmayı düşünür müsün?'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Evet, isterim.",
effects: {
happy: 10,
lust: 5
},
meta: {
type: "giselle_baby"
}
}, {
text: "Henüz hazır değilim.",
effects: {
happy: -5
}
}]
}, {
id: "giselle_trip",
text: "Giselle: 'Birlikte tatile çıkalım mı?'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Tatile çık. ($1500 harca)",
effects: {
happy: 10,
lust: 5
},
meta: {
type: "giselle_spend",
money: -1500
}
}, {
text: "Tatil için paramız yok.",
effects: {
happy: -5
}
}]
}, {
id: "giselle_friends",
text: "Giselle: 'Arkadaşlarımı davet edebilir miyim?'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Tabii, davet et.",
effects: {
happy: 5
}
}, {
text: "Hayır, bu akşam yalnız kalalım.",
effects: {
happy: -3
}
}]
}, {
id: "giselle_shoes",
text: "Giselle: 'Yeni ayakkabılar almak istiyorum.'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Ayakkabı al. ($250 harca)",
effects: {
happy: 5
},
meta: {
type: "giselle_spend",
money: -250
}
}, {
text: "Şu an alamayız.",
effects: {
happy: -3
}
}]
}, {
id: "giselle_movie",
text: "Giselle: 'Bu akşam sinemaya gidelim mi?'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Sinemaya git. ($100 harca)",
effects: {
happy: 5
},
meta: {
type: "giselle_spend",
money: -100
}
}, {
text: "Evde film izleyelim.",
effects: {
happy: 2
}
}]
}, {
id: "giselle_dress",
text: "Giselle: 'Yeni bir elbise almak istiyorum.'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Elbise al. ($350 harca)",
effects: {
happy: 5
},
meta: {
type: "giselle_spend",
money: -350
}
}, {
text: "Şu an alamayız.",
effects: {
happy: -3
}
}]
}, {
id: "giselle_jewelry",
text: "Giselle: 'Takı mağazasına gidelim mi?'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Takı al. ($200 harca)",
effects: {
happy: 5
},
meta: {
type: "giselle_spend",
money: -200
}
}, {
text: "Takı almayalım.",
effects: {
happy: -2
}
}]
}, {
id: "giselle_spa",
text: "Giselle: 'Birlikte spa'ya gidelim mi?'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Spa'ya git. ($400 harca)",
effects: {
happy: 7
},
meta: {
type: "giselle_spend",
money: -400
}
}, {
text: "Evde dinlenelim.",
effects: {
happy: 2
}
}]
}, {
id: "giselle_phone",
text: "Giselle: 'Yeni bir telefon almak istiyorum.'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Telefon al. ($1200 harca)",
effects: {
happy: 10
},
meta: {
type: "giselle_spend",
money: -1200
}
}, {
text: "Şu an alamayız.",
effects: {
happy: -5
}
}]
}, {
id: "giselle_bag",
text: "Giselle: 'Çantam eskidi, yenisini alabilir miyiz?'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Çanta al. ($300 harca)",
effects: {
happy: 5
},
meta: {
type: "giselle_spend",
money: -300
}
}, {
text: "Şu an alamayız.",
effects: {
happy: -3
}
}]
}, {
id: "giselle_makeup",
text: "Giselle: 'Kozmetik alışverişi yapalım mı?'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Kozmetik al. ($150 harca)",
effects: {
happy: 3
},
meta: {
type: "giselle_spend",
money: -150
}
}, {
text: "Hayır, gerek yok.",
effects: {
happy: -2
}
}]
}, {
id: "giselle_jacket",
text: "Giselle: 'Yeni bir ceket almak istiyorum.'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Ceket al. ($400 harca)",
effects: {
happy: 5
},
meta: {
type: "giselle_spend",
money: -400
}
}, {
text: "Şu an alamayız.",
effects: {
happy: -3
}
}]
}, {
id: "giselle_ring",
text: "Giselle: 'Yüzük bakmaya gidelim mi?'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Yüzük al. ($800 harca)",
effects: {
happy: 8
},
meta: {
type: "giselle_spend",
money: -800
}
}, {
text: "Yüzük almayalım.",
effects: {
happy: -3
}
}]
}, {
id: "giselle_baby2",
text: "Giselle: 'Bebek sahibi olmayı hâlâ düşünüyor musun?'",
portrait: "giselle",
speaker: "Giselle",
options: [{
text: "Evet, isterim.",
effects: {
happy: 10,
lust: 5
},
meta: {
type: "giselle_baby"
}
}, {
text: "Henüz hazır değilim.",
effects: {
happy: -5
}
}]
}];
// --- Ana story havuzu ---
var story = [
// Lisa kahvaltı - düşük ilişki
{
id: "lisa_breakfast_low",
text: "Lisa sabah kahvaltı hazırlamış ama aranız biraz soğuk. Mike ne der?",
portrait: 'lisa',
speaker: 'Lisa',
mood: "sad",
barCheck: {
key: "lisa",
max: 40
},
options: [{
text: "Yine mi aynı şey, biraz değişiklik yap.",
effects: {
lisa: -10,
happy: -5
},
meta: {
type: "truth"
},
next: null
}, {
text: "Teşekkür etmeden geçiştir.",
effects: {
lisa: -5
},
meta: {
type: "lie"
},
next: null
}]
},
// Lisa kahvaltı - orta ilişki
{
id: "lisa_breakfast_mid",
text: "Lisa sabah kahvaltı hazırlamış. Mike ne der?",
portrait: 'lisa',
speaker: 'Lisa',
mood: "neutral",
barCheck: {
key: "lisa",
min: 41,
max: 80
},
regretTrigger: "lied",
options: [{
text: "Çok güzel olmuş, teşekkür ederim.",
effects: {
lisa: 10,
happy: 5
},
next: null
}, {
text: "Yine mi aynı şey, biraz değişiklik yap.",
effects: {
lisa: -10,
happy: -5
},
meta: {
type: "lie"
},
next: null
}]
},
// Lisa kahvaltı - yüksek ilişki
{
id: "lisa_breakfast_high",
text: "Lisa sabah kahvaltı hazırlamış, aranız çok iyi. Mike ne der?",
portrait: 'lisa',
speaker: 'Lisa',
mood: "happy",
barCheck: {
key: "lisa",
min: 81
},
options: [{
text: "Sana her gün teşekkür etsem az, harikasın.",
effects: {
lisa: 10,
happy: 10
},
next: null
}, {
text: "Bugün de seninle kahvaltı yapmak çok güzel.",
effects: {
lisa: 5,
happy: 5
},
next: null
}]
},
// Rebecca sabah mesaj - düşük ilişki
{
id: "rebecca_morning_low",
text: "Rebecca sabah mesaj atıyor ama aranız biraz soğuk: 'Günaydın, öğle arasında buluşalım mı?'",
portrait: 'rebecca',
speaker: 'Rebecca',
mood: "sad",
barCheck: {
key: "rebecca",
max: 40
},
options: [{
text: "Şu an yoğunum, sonra konuşuruz.",
effects: {
rebecca: -5,
honest: 5
},
meta: {
type: "truth"
},
next: null
}, {
text: "Kısa cevap ver.",
effects: {
rebecca: -5
},
meta: {
type: "lie"
},
next: null
}]
},
// Rebecca sabah mesaj - orta ilişki
{
id: "rebecca_morning_mid",
text: "Rebecca sabah mesaj atıyor: 'Günaydın, öğle arasında buluşalım mı?'",
portrait: 'rebecca',
speaker: 'Rebecca',
mood: "neutral",
barCheck: {
key: "rebecca",
min: 41,
max: 80
},
options: [{
text: "Tabii, öğle arasında buluşalım.",
effects: {
rebecca: 10,
lust: 5,
betray: 5
},
next: null
}, {
text: "Şu an yoğunum, sonra konuşuruz.",
effects: {
rebecca: -5,
honest: 5
},
next: null
}]
},
// Rebecca sabah mesaj - yüksek ilişki
{
id: "rebecca_morning_high",
text: "Rebecca sabah mesaj atıyor, aranız çok iyi: 'Günaydın yakışıklı, öğle arasında buluşalım mı?'",
portrait: 'rebecca',
speaker: 'Rebecca',
mood: "happy",
barCheck: {
key: "rebecca",
min: 81
},
options: [{
text: "Seni görmek için sabırsızlanıyorum.",
effects: {
rebecca: 10,
lust: 10,
betray: 10
},
next: null
}, {
text: "Bugün işim var ama akşam konuşalım.",
effects: {
rebecca: 5,
honest: 5
},
next: null
}]
},
// ... (diğer orijinal story node'lar buraya eklenebilir, örnek olarak ilk iki olay çoğaltıldı)
// 3
{
text: "Patronun Alex seni sert bir şekilde eleştiriyor. Ne yaparsın?",
portrait: 'alex',
speaker: 'Alex',
mood: "angry",
options: [{
text: "Haklısınız, daha dikkatli olacağım.",
effects: {
alex: 10,
honest: 5,
happy: -5
},
next: null
}, {
text: "Bana fazla yükleniyorsunuz, adil değil.",
effects: {
alex: -10,
happy: -5
},
next: null
}]
},
// --- Ava: New story questions for more variety ---
{
text: "Lisa ile alışverişe çıktınız. Lisa yeni bir elbise almak istiyor.",
portrait: 'lisa',
speaker: 'Lisa',
options: [{
text: "Elbise almasına destek ol.",
effects: {
lisa: 10,
happy: 5
}
}, {
text: "Bütçemiz kısıtlı, başka zaman alalım.",
effects: {
lisa: -5,
honest: 5
}
}]
}, {
text: "Rebecca iş yerinde sana bir sır veriyor.",
portrait: 'rebecca',
speaker: 'Rebecca',
options: [{
text: "Sırrını sakla.",
effects: {
rebecca: 10,
honest: 5
}
}, {
text: "Sırrı başkasına anlat.",
effects: {
rebecca: -10,
betray: 10
}
}]
}, {
text: "Peter ile futbol maçı izliyorsunuz.",
portrait: 'peter',
speaker: 'Peter',
options: [{
text: "Beraber tezahürat yap.",
effects: {
peter: 10,
happy: 5
}
}, {
text: "Maçtan sıkıldığını söyle.",
effects: {
peter: -5
}
}]
}, {
text: "Alex yeni bir iş fırsatı sunuyor.",
portrait: 'alex',
speaker: 'Alex',
options: [{
text: "Fırsatı kabul et.",
effects: {
alex: 10,
happy: 5
}
}, {
text: "Reddet, mevcut işinden memnunsun.",
effects: {
alex: -5,
honest: 5
}
}]
}, {
text: "Lisa ile tartıştınız. Lisa üzgün.",
portrait: 'lisa',
speaker: 'Lisa',
options: [{
text: "Özür dile.",
effects: {
lisa: 10,
honest: 5
}
}, {
text: "Haklı olduğunu savun.",
effects: {
lisa: -10
}
}]
}, {
text: "Rebecca ile sinemaya gitme planı yapıyorsun.",
portrait: 'rebecca',
speaker: 'Rebecca',
options: [{
text: "Romantik bir film seç.",
effects: {
rebecca: 10,
lust: 5
}
}, {
text: "Aksiyon filmi seç.",
effects: {
rebecca: 5
}
}]
}, {
text: "Peter sana bir kitap öneriyor.",
portrait: 'peter',
speaker: 'Peter',
options: [{
text: "Kitabı oku ve yorum yap.",
effects: {
peter: 10,
honest: 5
}
}, {
text: "Kitabı okumadığını itiraf et.",
effects: {
peter: -5,
honest: 5
}
}]
}, {
text: "Alex ile iş seyahatine çıkıyorsun.",
portrait: 'alex',
speaker: 'Alex',
options: [{
text: "Alex ile yakınlaş.",
effects: {
alex: 10,
betray: 5
}
}, {
text: "Mesafeni koru.",
effects: {
alex: 5,
honest: 5
}
}]
}, {
text: "Lisa sana sürpriz bir doğum günü partisi hazırlıyor.",
portrait: 'lisa',
speaker: 'Lisa',
options: [{
text: "Çok mutlu ol ve teşekkür et.",
effects: {
lisa: 10,
happy: 10
}
}, {
text: "Sürprizleri sevmediğini söyle.",
effects: {
lisa: -5,
honest: 5
}
}]
}, {
text: "Rebecca ile bir tartışma yaşıyorsun.",
portrait: 'rebecca',
speaker: 'Rebecca',
options: [{
text: "Barışmak için adım at.",
effects: {
rebecca: 10
}
}, {
text: "Tartışmayı uzat.",
effects: {
rebecca: -10
}
}]
}, {
text: "Peter ile eski bir fotoğraf albümüne bakıyorsun.",
portrait: 'peter',
speaker: 'Peter',
options: [{
text: "Güzel anıları hatırla.",
effects: {
peter: 10,
happy: 5
}
}, {
text: "Geçmişi konuşmak istemediğini söyle.",
effects: {
peter: -5
}
}]
}, {
text: "Alex iş yerinde seni övüyor.",
portrait: 'alex',
speaker: 'Alex',
options: [{
text: "Teşekkür et.",
effects: {
alex: 10,
happy: 5
}
}, {
text: "Mütevazı davran.",
effects: {
alex: 5
}
}]
}, {
text: "Lisa ile birlikte yemek yapıyorsun.",
portrait: 'lisa',
speaker: 'Lisa',
options: [{
text: "Birlikte eğlenerek yemek yap.",
effects: {
lisa: 10,
happy: 5
}
}, {
text: "Yemek yapmayı sevmediğini söyle.",
effects: {
lisa: -5
}
}]
}, {
text: "Rebecca yeni bir hobiye başlamak istiyor.",
portrait: 'rebecca',
speaker: 'Rebecca',
options: [{
text: "Onu destekle.",
effects: {
rebecca: 10
}
}, {
text: "Hobisini gereksiz bul.",
effects: {
rebecca: -5
}
}]
}, {
text: "Peter ile bir iş projesinde çalışıyorsun.",
portrait: 'peter',
speaker: 'Peter',
options: [{
text: "Peter'ın fikirlerine değer ver.",
effects: {
peter: 10
}
}, {
text: "Kendi bildiğini yap.",
effects: {
peter: -5
}
}]
}, {
text: "Alex ile bir anlaşmazlık yaşıyorsun.",
portrait: 'alex',
speaker: 'Alex',
options: [{
text: "Uzlaşmacı ol.",
effects: {
alex: 10
}
}, {
text: "Kendi fikrinde ısrar et.",
effects: {
alex: -5
}
}]
},
// 3
{
text: "Patronun Alex seni sert bir şekilde eleştiriyor. Ne yaparsın?",
portrait: 'alex',
speaker: 'Alex',
mood: "angry",
options: [{
text: "Haklısınız, daha dikkatli olacağım.",
effects: {
alex: 10,
honest: 5,
happy: -5
},
next: null
}, {
text: "Bana fazla yükleniyorsunuz, adil değil.",
effects: {
alex: -10,
happy: -5
},
next: null
}]
},
// 4
{
text: "Peter zor durumda olduğunu söylüyor. Ne yaparsın?",
portrait: 'peter',
speaker: 'Peter',
mood: "sad",
options: [{
text: "Yanındayım, neye ihtiyacın varsa söyle.",
effects: {
peter: 10,
happy: 5
},
next: null
}, {
text: "Kendi işimle meşgulüm, üzgünüm.",
effects: {
peter: -10,
happy: -5
},
next: null
}]
},
// 5
{
text: "Lisa seninle dürüstçe konuşmak istiyor. Ne yaparsın?",
portrait: 'lisa',
speaker: 'Lisa',
options: [{
text: "Tabii, ne söylemek istiyorsan dinliyorum.",
effects: {
lisa: 10,
honest: 10
},
next: null
}, {
text: "Bunları konuşmak istemiyorum.",
effects: {
lisa: -10,
honest: -10
},
next: null
}]
},
// 6
{
text: "Rebecca ile ofiste samimi bir an yaşıyorsun. Lisa yanında.",
portrait: 'rebecca',
speaker: 'Rebecca',
options: [{
text: "Lisa burada, sonra konuşalım.",
effects: {
rebecca: -5,
honest: 5
},
next: null
}, {
text: "Hemen sana geliyorum.",
effects: {
rebecca: 10,
lisa: -10,
betray: 10
},
next: null
}]
},
// 7
{
text: "Yorgunsun, Lisa dışarı çıkmak istiyor.",
portrait: 'lisa',
speaker: 'Lisa',
options: [{
text: "Bugün yorgunum, evde kalalım.",
effects: {
lisa: -5,
happy: -5
},
next: null
}, {
text: "Tamam, seninle dışarı çıkalım.",
effects: {
lisa: 10,
happy: 5
},
next: null
}]
},
// 8
{
text: "Alex önemli bir projeyi sana teslim etti.",
portrait: 'alex',
speaker: 'Alex',
mood: "neutral",
options: [{
text: "Gerçekçi zaman verirsek başarı şansı artar.",
effects: {
alex: 10,
honest: 10
},
next: null
}, {
text: "Mümkün olduğunca hızlı yapacağım, sorun yok.",
effects: {
alex: -5,
happy: 5
},
next: null
}]
},
// 9
{
text: "Peter geçmişte yaptığın bir hatayı hatırlatıyor.",
portrait: 'peter',
speaker: 'Peter',
mood: "angry",
regretTrigger: "ignored_peter",
options: [{
text: "Haklısın, özür dilerim.",
effects: {
peter: 10,
honest: 10
},
next: null
}, {
text: "O günler geçti, unutalım.",
effects: {
peter: -10
},
meta: {
ignoreRegret: true
},
next: null
}]
},
// 10
{
text: "Lisa bir sır sakladığını düşünüyor.",
portrait: 'lisa',
speaker: 'Lisa',
regretTrigger: "betrayed_lisa",
options: [{
text: "Sana her şeyi anlatacağım.",
effects: {
lisa: 10,
honest: 10
},
next: null
}, {
text: "Beni yanlış anlıyorsun.",
effects: {
lisa: -10,
honest: -10
},
meta: {
type: "lie"
},
next: null
}]
},
// 11
{
text: "Rebecca ile iş çıkışı kafede buluşuyorsun.",
portrait: 'rebecca',
speaker: 'Rebecca',
options: [{
text: "Rebecca ile samimi bir sohbet et.",
effects: {
rebecca: 10,
lust: 10,
betray: 5
},
next: null
}, {
text: "Kısa kesip eve git.",
effects: {
rebecca: -5,
lisa: 5,
honest: 5
},
next: null
}]
},
// 12
{
text: "Alex seni fazla mesaiye bırakmak istiyor.",
portrait: 'alex',
speaker: 'Alex',
mood: "neutral",
options: [{
text: "Kabul et, işini bitir.",
effects: {
alex: 10,
happy: -5
},
next: null
}, {
text: "Reddet, eve git.",
effects: {
alex: -10,
lisa: 5,
happy: 5
},
next: null
}]
},
// 13
{
text: "Peter ile eski günlerden konuşuyorsun.",
portrait: 'peter',
speaker: 'Peter',
mood: "happy",
options: [{
text: "Duygusal bir anı paylaş.",
effects: {
peter: 10,
happy: 5
},
next: null
}, {
text: "Geçmişi geçiştir.",
effects: {
peter: -5
},
next: null
}]
},
// 14
{
text: "Lisa ile romantik bir akşam yemeği.",
portrait: 'lisa',
speaker: 'Lisa',
options: [{
text: "Lisa'ya iltifat et.",
effects: {
lisa: 10,
happy: 10,
lust: 5
},
next: null
}, {
text: "Yemekle ilgilenme, telefona bak.",
effects: {
lisa: -10,
happy: -5,
lust: -5
},
next: null
}]
},
// 15
{
text: "Rebecca işte sana yardım ediyor.",
portrait: 'rebecca',
speaker: 'Rebecca',
options: [{
text: "Teşekkür et, birlikte çalış.",
effects: {
rebecca: 10,
honest: 5
},
next: null
}, {
text: "Yardımı reddet.",
effects: {
rebecca: -5
},
next: null
}]
},
// 16
{
text: "Alex işte bir hata buldu.",
portrait: 'alex',
speaker: 'Alex',
mood: "angry",
options: [{
text: "Hatanı kabul et.",
effects: {
alex: 5,
honest: 10
},
next: null
}, {
text: "Suçu başkasına at.",
effects: {
alex: -10,
honest: -10,
betray: 10
},
next: null
}]
},
// 17
{
text: "Peter ile tartıştın.",
portrait: 'peter',
speaker: 'Peter',
mood: "angry",
options: [{
text: "Barışmak için adım at.",
effects: {
peter: 10,
honest: 5
},
next: null
}, {
text: "Görmezden gel.",
effects: {
peter: -10,
happy: -5
},
next: null
}]
},
// 18
{
text: "Lisa ile hafta sonu planı yapıyorsun.",
portrait: 'lisa',
speaker: 'Lisa',
options: [{
text: "Birlikte sinemaya git.",
effects: {
lisa: 10,
happy: 5
},
next: null
}, {
text: "Evde kalmayı teklif et.",
effects: {
lisa: -5,
happy: 5
},
next: null
}]
},
// 19
{
text: "Rebecca ile iş gezisine çıkıyorsun.",
portrait: 'rebecca',
speaker: 'Rebecca',
options: [{
text: "Samimi davran.",
effects: {
rebecca: 10,
lust: 10,
betray: 5
},
next: null
}, {
text: "Mesafeni koru.",
effects: {
rebecca: -5,
honest: 5
},
next: null
}]
},
// 20
{
text: "Alex yeni bir görev veriyor.",
portrait: 'alex',
speaker: 'Alex',
mood: "neutral",
options: [{
text: "Görevi kabul et.",
effects: {
alex: 10,
happy: 5
},
next: null
}, {
text: "Görevi reddet.",
effects: {
alex: -10,
happy: -5
},
next: null
}]
}];
// --- State ---
// Relationship values (0-100)
var rel_lisa = 50;
var rel_rebecca = 50;
var rel_peter = 50;
var rel_alex = 50;
// Bars (0-100)
var bar_happy = 50;
var bar_honest = 50;
var bar_lust = 50;
var bar_betray = 50;
// --- Shadow bar (0-100, hidden from player) ---
var bar_shadow = 0;
// Bar-based flags (for special scenes/endings)
var flags = {};
// Track important past choices for memory mechanic
var pastChoices = [];
// Turn counter for time-based triggers
var turnCount = 0;
// --- Ava: Time, salary, baby, pregnancy, money mechanics ---
var dayCount = 1; // 1-based, every 2 questions = 1 day
var mikeSalary = 100;
var mikeMoney = 0;
var mikeBabyCount = 0;
var lisaPregnant = false;
var rebeccaPregnant = false;
var gisellePregnant = false;
var showLisaPregOption = false;
var showRebeccaPregOption = false;
var showGisellePregOption = false;
var giselleUnlocked = false; // Satın alındı mı?
var shopItemStates = [false, false, false, false]; // 0: Giselle, 1-3: diğerleri
// --- UI Elements ---
// Portrait
var portraitNode = null;
// Speaker name
var speakerText = null;
// Story text
var storyText = null;
// Option buttons
var optionButtons = [];
// Relationship bars
var barNodes = {};
// Karakter portreleri ve ilişki dereceleri için UI
var characterPortraits = [];
var characterLabels = [];
// --- Ava: UI for day, salary, money, baby count ---
var dayText = null;
var salaryText = null;
var moneyText = null;
var babyText = null;
// --- Functions ---
// getNextNode: uygun story node'unu bar değerine göre seç
// --- Ava: Prevent same question from repeating within last 20, and add more questions ---
var lastStoryIndices = [];
function getNextNode() {
// Tüm story node'larını karıştır
var indices = [];
for (var i = 0; i < story.length; i++) {
indices.push(i);
}
// Fisher-Yates shuffle
for (var i = indices.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = indices[i];
indices[i] = indices[j];
indices[j] = temp;
}
// Ava: Filter out nodes that were used in the last 20
var filteredIndices = [];
for (var k = 0; k < indices.length; k++) {
var idx = indices[k];
if (lastStoryIndices.indexOf(idx) === -1) {
filteredIndices.push(idx);
}
}
// If less than 5 available, allow all (reset)
var useIndices = filteredIndices.length > 5 ? filteredIndices : indices;
// --- Giselle: Eğer satın alındıysa, havuza Giselle sorularını da ekle ---
// --- Whiskey: Eğer satın alındıysa, havuza Whiskey sorularını da ekle ---
// --- Villa: Eğer satın alındıysa, havuza Villa event ve sorularını da ekle ---
var pool = [];
for (var k = 0; k < useIndices.length; k++) {
var idx = useIndices[k];
var node = story[idx];
// Sadece Giselle alınmışsa Giselle soruları havuza eklenir
if (node && node.portrait === "giselle" && !giselleUnlocked) continue;
// Sadece Whiskey alınmışsa Whiskey soruları havuza eklenir
if (node && node.portrait === "whiskey" && !whiskeyUnlocked) continue;
// Villa eventleri ve soruları sadece villaUnlocked ise eklenir
if (node && node.id && node.id.indexOf("villa_") === 0 && !villaUnlocked) continue;
pool.push({
idx: idx,
node: node
});
}
if (giselleUnlocked) {
// Son 20'de olmayan Giselle sorularını da ekle
for (var g = 0; g < giselleQuestions.length; g++) {
var gq = giselleQuestions[g];
var gqId = "giselle_" + g;
// Sadece son 20'de yoksa ekle
var alreadyUsed = false;
for (var h = 0; h < lastStoryIndices.length; h++) {
if (story[lastStoryIndices[h]] && story[lastStoryIndices[h]].id === gq.id) alreadyUsed = true;
}
if (!alreadyUsed) {
pool.push({
idx: -1,
node: gq
});
}
}
}
if (whiskeyUnlocked) {
// Son 20'de olmayan Whiskey sorularını da ekle
for (var w = 0; w < whiskeyQuestions.length; w++) {
var wq = whiskeyQuestions[w];
var wqId = "whiskey_" + w;
var alreadyUsedW = false;
for (var h = 0; h < lastStoryIndices.length; h++) {
if (story[lastStoryIndices[h]] && story[lastStoryIndices[h]].id === wq.id) alreadyUsedW = true;
}
if (!alreadyUsedW) {
pool.push({
idx: -1,
node: wq
});
}
}
}
if (villaUnlocked) {
// Son 20'de olmayan Villa invite eventlerini ekle
for (var v = 0; v < villaInviteEvents.length; v++) {
var ve = villaInviteEvents[v];
var alreadyUsedV = false;
for (var h = 0; h < lastStoryIndices.length; h++) {
if (story[lastStoryIndices[h]] && story[lastStoryIndices[h]].id === ve.id) alreadyUsedV = true;
}
if (!alreadyUsedV) {
pool.push({
idx: -1,
node: ve
});
}
}
// Son 20'de olmayan Villa özel sorularını ekle
for (var vq = 0; vq < villaSpecialQuestions.length; vq++) {
var vsq = villaSpecialQuestions[vq];
var alreadyUsedVSQ = false;
for (var h = 0; h < lastStoryIndices.length; h++) {
if (story[lastStoryIndices[h]] && story[lastStoryIndices[h]].id === vsq.id) alreadyUsedVSQ = true;
}
if (!alreadyUsedVSQ) {
pool.push({
idx: -1,
node: vsq
});
}
}
}
// Her bir node'u sırayla kontrol et, barCheck varsa uygun olanı döndür
for (var k = 0; k < pool.length; k++) {
var idx = pool[k].idx;
var node = pool[k].node;
if (!node.options || node.options.length === 0) continue;
if (node.barCheck) {
var key = node.barCheck.key;
var min = typeof node.barCheck.min === "number" ? node.barCheck.min : -Infinity;
var max = typeof node.barCheck.max === "number" ? node.barCheck.max : Infinity;
var val = 0;
if (key === "lisa") val = rel_lisa;else if (key === "rebecca") val = rel_rebecca;else if (key === "peter") val = rel_peter;else if (key === "alex") val = rel_alex;else if (key === "happy") val = bar_happy;else if (key === "honest") val = bar_honest;else if (key === "lust") val = bar_lust;else if (key === "betray") val = bar_betray;
if (val >= min && val <= max) {
lastStoryIndices.push(idx);
if (lastStoryIndices.length > 20) lastStoryIndices.shift();
return idx;
}
} else {
lastStoryIndices.push(idx);
if (lastStoryIndices.length > 20) lastStoryIndices.shift();
return idx;
}
}
// Hiçbiri uygun değilse ilk node'u döndür
lastStoryIndices.push(0);
if (lastStoryIndices.length > 20) lastStoryIndices.shift();
return 0;
}
function resetGameState() {
rel_lisa = 50;
rel_rebecca = 50;
rel_peter = 50;
rel_alex = 50;
bar_happy = 50;
bar_honest = 50;
bar_lust = 50;
bar_betray = 50;
bar_shadow = 0;
flags = {};
pastChoices = [];
turnCount = 0;
currentNode = 0;
// Reset dramatic system
nextDramaticTurn = 4 + Math.floor(Math.random() * 3);
dramaticHistory = [];
if (game._dramaticShadow) {
game.removeChild(game._dramaticShadow);
game._dramaticShadow = null;
}
dayCount = 1;
mikeSalary = 100;
mikeMoney = 0;
mikeBabyCount = 0;
lisaPregnant = false;
rebeccaPregnant = false;
gisellePregnant = false;
giselleUnlocked = false;
whiskeyUnlocked = false;
villaUnlocked = false;
shopItemStates = [false, false, false, false];
if (storage) {
storage.mikeMoney = 0;
storage.mikeSalary = 100;
storage.mikeBabyCount = 0;
storage.dayCount = 1;
storage.lisaPregnant = false;
storage.rebeccaPregnant = false;
storage.gisellePregnant = false;
storage.giselleUnlocked = false;
storage.whiskeyUnlocked = false;
storage.villaUnlocked = false;
}
}
function createUI() {
// Portrait
if (portraitNode) game.removeChild(portraitNode);
portraitNode = LK.getAsset('mike', {
anchorX: 0.5,
anchorY: 0.5
});
// Mike portresini ve karakteri ekrana tam ortala
portraitNode.x = 2048 / 2;
portraitNode.y = 520;
game.addChild(portraitNode);
// --- Mike portresine titreme animasyonu ekle ---
function shakePortrait(node) {
if (!node) return;
var origX = 2048 / 2;
var origY = 520;
function doShake() {
// Rastgele küçük bir ofset (±8px)
var dx = (Math.random() - 0.5) * 16;
var dy = (Math.random() - 0.5) * 10;
tween(node, {
x: origX + dx,
y: origY + dy
}, {
duration: 80,
easing: tween.linear,
onFinish: function onFinish() {
tween(node, {
x: origX,
y: origY
}, {
duration: 80,
easing: tween.linear,
onFinish: function onFinish() {
LK.setTimeout(doShake, 80 + Math.floor(Math.random() * 60));
}
});
}
});
}
doShake();
}
shakePortrait(portraitNode);
// --- Eğer ilgili karakter portresi varsa ona da titreme ekle ---
if (game.relatedPortraitNode) {
var _shakeRelated = function shakeRelated() {
if (!relNode.parent) return; // Silindiyse dur
var dx = (Math.random() - 0.5) * 16;
var dy = (Math.random() - 0.5) * 10;
tween(relNode, {
x: relOrigX + dx,
y: relOrigY + dy
}, {
duration: 80,
easing: tween.linear,
onFinish: function onFinish() {
tween(relNode, {
x: relOrigX,
y: relOrigY
}, {
duration: 80,
easing: tween.linear,
onFinish: function onFinish() {
LK.setTimeout(_shakeRelated, 80 + Math.floor(Math.random() * 60));
}
});
}
});
};
var relNode = game.relatedPortraitNode;
var relOrigX = relNode.x;
var relOrigY = relNode.y;
_shakeRelated();
}
// Speaker (isim) biraz daha aşağıda
if (speakerText) game.removeChild(speakerText);
speakerText = new Text2('', {
size: 64,
fill: '#ffffff'
});
speakerText.anchor.set(0.5, 0.5);
speakerText.x = 2048 / 2;
speakerText.y = 740;
game.addChild(speakerText);
// Story text (olay) biraz daha aşağıda
if (storyText) game.removeChild(storyText);
storyText = new Text2('', {
size: 54,
fill: '#ffffff',
wordWrap: true,
wordWrapWidth: 1800
});
storyText.anchor.set(0.5, 0);
storyText.x = 2048 / 2;
storyText.y = 830;
game.addChild(storyText);
// Relationship bars
var barNames = [{
key: 'happy',
label: 'Mutluluk',
y: 1100,
val: bar_happy
}, {
key: 'honest',
label: 'Dürüstlük',
y: 1180,
val: bar_honest
}, {
key: 'lust',
label: 'Şehvet',
y: 1260,
val: bar_lust
}, {
key: 'betray',
label: 'İhanet',
y: 1340,
val: bar_betray
}];
for (var i = 0; i < barNames.length; i++) {
var b = barNames[i];
if (barNodes[b.key]) game.removeChild(barNodes[b.key]);
var bar = new RelationshipBar();
bar.setType(b.key);
bar.setValue(b.val);
// Bar ismi ve yüzdeyi birlikte göster
if (bar.label) bar.removeChild(bar.label);
bar.label = new Text2(b.label + ' (' + b.val + '%)', {
size: 36,
fill: '#ffffff'
});
bar.label.anchor.set(1, 0.5);
bar.label.x = bar.maxWidth + 20;
bar.label.y = 20;
bar.addChild(bar.label);
bar.x = 2048 / 2 - 200;
bar.y = b.y;
game.addChild(bar);
barNodes[b.key] = bar;
}
// Karakter portreleri ve ilişki dereceleri (en altta)
for (var i = 0; i < characterPortraits.length; i++) {
game.removeChild(characterPortraits[i]);
}
for (var i = 0; i < characterLabels.length; i++) {
game.removeChild(characterLabels[i]);
}
characterPortraits = [];
characterLabels = [];
var chars = [{
key: 'lisa',
label: 'Lisa',
rel: rel_lisa
}, {
key: 'rebecca',
label: 'Rebecca',
rel: rel_rebecca
}, {
key: 'peter',
label: 'Peter',
rel: rel_peter
}, {
key: 'alex',
label: 'Alex',
rel: rel_alex
}];
var startX = 2048 / 2 - 400 - 60;
var y = 2600;
for (var i = 0; i < chars.length; i++) {
var c = chars[i];
var portrait = LK.getAsset(c.key, {
anchorX: 0.5,
anchorY: 1
});
portrait.x = startX + i * 270;
portrait.y = y;
game.addChild(portrait);
characterPortraits.push(portrait);
var label = new Text2(c.label + ': ' + c.rel + '%', {
size: 44,
fill: '#ffffff'
});
label.anchor.set(0.5, 0);
label.x = portrait.x;
label.y = y + 10;
game.addChild(label);
characterLabels.push(label);
}
// --- Ava: Add day, salary, money, baby count UI ---
if (dayText) game.removeChild(dayText);
if (salaryText) game.removeChild(salaryText);
if (moneyText) game.removeChild(moneyText);
if (babyText) game.removeChild(babyText);
dayText = new Text2('Gün: ' + dayCount, {
size: 54,
fill: '#fff'
});
dayText.anchor.set(0, 0);
dayText.x = 120;
dayText.y = 80;
game.addChild(dayText);
salaryText = new Text2('Maaş: $' + mikeSalary, {
size: 54,
fill: '#fff'
});
salaryText.anchor.set(0, 0);
salaryText.x = 120;
salaryText.y = 150;
game.addChild(salaryText);
moneyText = new Text2('Para: $' + mikeMoney, {
size: 54,
fill: '#fff'
});
moneyText.anchor.set(0, 0);
moneyText.x = 120;
moneyText.y = 220;
game.addChild(moneyText);
babyText = new Text2('Bebek: ' + mikeBabyCount, {
size: 54,
fill: '#fff'
});
babyText.anchor.set(0, 0);
babyText.x = 120;
babyText.y = 290;
game.addChild(babyText);
// --- Ava: Show relationship options if eligible ---
// Remove old relationship option buttons if any
if (game._relOptionBtns) {
for (var i = 0; i < game._relOptionBtns.length; i++) {
game.removeChild(game._relOptionBtns[i]);
}
}
game._relOptionBtns = [];
// --- Shop/Store UI (right side, vertical) ---
if (game._shopNodes) {
for (var i = 0; i < game._shopNodes.length; i++) {
game.removeChild(game._shopNodes[i]);
}
}
game._shopNodes = [];
var shopAssetIds = ['giselle', 'shop_item2', 'shop_item3', 'shop_item4'];
var shopPrices = [10000, 2500, 50000, 7500];
var shopLabels = ['Giselle', 'Whiskey', 'Villa', 'Eşya 4'];
var shopYStart = 1200; // moved even further down
var shopSpacing = 450; // even more space between items
// --- Villa state ---
if (typeof villaUnlocked === "undefined") villaUnlocked = false;
if (typeof whiskeyUnlocked === "undefined") whiskeyUnlocked = false;
for (var i = 0; i < 4; i++) {
var assetId = shopAssetIds[i];
var node = LK.getAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
node.x = 2048 - 120;
node.y = shopYStart + i * shopSpacing;
node.scale.x = node.scale.y = 1.0;
// Shop items are passive (dimmed, not interactive) until purchased, then active
if (shopItemStates[i]) {
node.alpha = 1.0;
node.interactive = false;
node.buttonMode = false;
} else {
node.alpha = 0.5;
node.interactive = true;
node.buttonMode = true;
}
// Price label (above the item)
var priceText = "";
if (i === 0) {
priceText = "$10,000";
} else if (i === 1) {
priceText = "$2,500";
} else if (i === 2) {
priceText = "$50,000";
} else if (i === 3) {
priceText = "$7,500";
}
var priceLabel = new Text2(priceText, {
size: 38,
fill: '#ffe066',
fontWeight: 'bold'
});
priceLabel.anchor.set(0.5, 1);
priceLabel.x = node.x;
priceLabel.y = node.y - node.height / 2 - 12;
game.addChild(priceLabel);
game._shopNodes.push(priceLabel);
// Name label (below the item)
var label = new Text2(shopLabels[i], {
size: 36,
fill: '#fff',
wordWrap: true,
wordWrapWidth: 180
});
label.anchor.set(0.5, 0);
label.x = node.x;
label.y = node.y + node.height / 2 + 10;
game.addChild(node);
game.addChild(label);
game._shopNodes.push(node, label);
// Giselle buy logic
if (i === 0 && !giselleUnlocked) {
node.down = function () {
if (mikeMoney >= 10000) {
mikeMoney -= 10000;
giselleUnlocked = true;
shopItemStates[0] = true;
// After purchase, make the item active (full alpha, not interactive)
node.alpha = 1.0;
node.interactive = false;
node.buttonMode = false;
updateBars();
createUI();
} else {
// Not enough money, flash red
tween(node, {
alpha: 0.3
}, {
duration: 120,
onFinish: function onFinish() {
tween(node, {
alpha: 1
}, {
duration: 120
});
}
});
}
};
}
// Whiskey buy logic
if (i === 1 && !whiskeyUnlocked) {
node.down = function () {
if (mikeMoney >= 2500) {
mikeMoney -= 2500;
whiskeyUnlocked = true;
shopItemStates[1] = true;
// After purchase, make the item active (full alpha, not interactive)
node.alpha = 1.0;
node.interactive = false;
node.buttonMode = false;
updateBars();
createUI();
} else {
// Not enough money, flash red
tween(node, {
alpha: 0.3
}, {
duration: 120,
onFinish: function onFinish() {
tween(node, {
alpha: 1
}, {
duration: 120
});
}
});
}
};
}
// Villa buy logic
if (i === 2 && !villaUnlocked) {
node.down = function () {
if (mikeMoney >= 50000) {
mikeMoney -= 50000;
villaUnlocked = true;
shopItemStates[2] = true;
// After purchase, make the item active (full alpha, not interactive)
node.alpha = 1.0;
node.interactive = false;
node.buttonMode = false;
updateBars();
createUI();
} else {
tween(node, {
alpha: 0.3
}, {
duration: 120,
onFinish: function onFinish() {
tween(node, {
alpha: 1
}, {
duration: 120
});
}
});
}
};
}
}
// Lisa
if (rel_lisa > 70 && !lisaPregnant) {
var btnLisa = new OptionButton();
btnLisa.setText("Lisa ile ilişkiye gir");
btnLisa.x = 2048 - 400;
btnLisa.y = 80;
btnLisa.setCallback(function () {
// %30 hamile kalma şansı
if (Math.random() < 0.3) {
lisaPregnant = true;
showStoryNode(currentNode);
}
});
game.addChild(btnLisa);
game._relOptionBtns.push(btnLisa);
}
// Rebecca
if (rel_rebecca > 70 && !rebeccaPregnant) {
var btnRebecca = new OptionButton();
btnRebecca.setText("Rebecca ile ilişkiye gir");
btnRebecca.x = 2048 - 400;
btnRebecca.y = 220;
btnRebecca.setCallback(function () {
if (Math.random() < 0.3) {
rebeccaPregnant = true;
showStoryNode(currentNode);
}
});
game.addChild(btnRebecca);
game._relOptionBtns.push(btnRebecca);
}
// Giselle
if (giselleUnlocked && !gisellePregnant) {
var btnGiselle = new OptionButton();
btnGiselle.setText("Giselle ile ilişkiye gir");
btnGiselle.x = 2048 - 400;
btnGiselle.y = 360;
btnGiselle.setCallback(function () {
if (Math.random() < 0.3) {
gisellePregnant = true;
showStoryNode(currentNode);
}
});
game.addChild(btnGiselle);
game._relOptionBtns.push(btnGiselle);
}
}
function updateBars() {
if (typeof villaUnlocked !== "undefined" && villaUnlocked && bar_happy < 80) {
bar_happy = 80;
}
barNodes['happy'].setValue(bar_happy);
barNodes['honest'].setValue(bar_honest);
barNodes['lust'].setValue(bar_lust);
barNodes['betray'].setValue(bar_betray);
// Bar isimleri ve yüzdeleri birlikte güncellensin
barNodes['happy'].label.setText('Mutluluk (' + bar_happy + '%)');
barNodes['honest'].label.setText('Dürüstlük (' + bar_honest + '%)');
barNodes['lust'].label.setText('Şehvet (' + bar_lust + '%)');
barNodes['betray'].label.setText('İhanet (' + bar_betray + '%)');
// Karakter ilişki dereceleri güncellensin
var rels = [rel_lisa, rel_rebecca, rel_peter, rel_alex];
var _loop = function _loop() {
names = ['Lisa', 'Rebecca', 'Peter', 'Alex'];
label = characterLabels[i];
prevText = label.text;
newText = names[i] + ': ' + rels[i] + '%'; // Değer değiştiyse animasyon başlat
if (prevText !== newText) {
// Son değeri bul
prevVal = 0;
match = prevText && prevText.match(/: (\-?\d+)%/);
if (match) prevVal = parseInt(match[1]);
newVal = rels[i]; // Pozitif veya negatif değişim: sadece etkilenen karakter titresin
if (newVal > prevVal || newVal < prevVal) {
// Sadece ilişki değeri değişen karakter titresin
portrait = characterPortraits[i];
if (portrait) {
var _doShakeChar = function doShakeChar() {
if (!portrait.parent || shakeCount >= 6) {
// Titreme bitti, orijinal konuma dön
portrait.x = origX;
portrait.y = origY;
return;
}
var dx = (Math.random() - 0.5) * 16;
var dy = (Math.random() - 0.5) * 10;
tween(portrait, {
x: origX + dx,
y: origY + dy
}, {
duration: 50,
easing: tween.linear,
onFinish: function onFinish() {
tween(portrait, {
x: origX,
y: origY
}, {
duration: 50,
easing: tween.linear,
onFinish: function onFinish() {
shakeCount++;
LK.setTimeout(_doShakeChar, 10);
}
});
}
});
};
// Titreme animasyonu uygula
origX = portrait.x;
origY = portrait.y;
shakeCount = 0;
_doShakeChar();
}
}
if (newVal > prevVal) {
if (label.style) label.style.fill = '#00ff00';
tween(label, {
alpha: 0.3
}, {
duration: 120,
easing: tween.linear,
onFinish: function (lbl) {
tween(lbl, {
alpha: 1
}, {
duration: 120,
easing: tween.linear,
onFinish: function (lbl2) {
if (lbl2.style) lbl2.style.fill = '#ffffff';
}.bind(null, label)
});
}.bind(null, label)
});
} else if (newVal < prevVal) {
if (label.style) label.style.fill = '#ff2222';
tween(label, {
alpha: 0.3
}, {
duration: 120,
easing: tween.linear,
onFinish: function (lbl) {
tween(lbl, {
alpha: 1
}, {
duration: 120,
easing: tween.linear,
onFinish: function (lbl2) {
if (lbl2.style) lbl2.style.fill = '#ffffff';
}.bind(null, label)
});
}.bind(null, label)
});
}
}
label.setText(newText);
},
names,
label,
prevText,
newText,
prevVal,
match,
newVal,
portrait,
origX,
origY,
shakeCount;
for (var i = 0; i < characterLabels.length; i++) {
_loop();
}
// --- Ava: Update day, salary, money, baby count UI ---
if (dayText) dayText.setText('Gün: ' + dayCount);
if (salaryText) salaryText.setText('Maaş: $' + mikeSalary);
if (moneyText) moneyText.setText('Para: $' + mikeMoney);
if (babyText) babyText.setText('Bebek: ' + mikeBabyCount);
// Refresh relationship option buttons
if (typeof createUI === "function") {
// Only refresh if UI is visible (avoid infinite loop)
if (game && typeof game._relOptionBtns !== "undefined") {
createUI();
}
}
}
function showStoryNode(idx) {
// Remove old option buttons
for (var i = 0; i < optionButtons.length; i++) {
game.removeChild(optionButtons[i]);
}
optionButtons = [];
// Dramatic choice injection: if turnCount >= nextDramaticTurn, show dramatic choice instead
if (typeof nextDramaticTurn !== "undefined" && turnCount >= nextDramaticTurn) {
showDramaticChoice();
return;
}
var node = story[idx];
// Portrait
if (portraitNode) {
if (node.portrait && LK.getAsset(node.portrait, {})) {
portraitNode.texture = LK.getAsset(node.portrait, {}).texture;
}
// Mood-based tint or background for Lisa, Rebecca, Mike, Peter, Alex
if (node.mood && (node.portrait === "lisa" || node.portrait === "rebecca" || node.portrait === "mike" || node.portrait === "peter" || node.portrait === "alex")) {
// Mood to tint mapping
var moodTints = {
happy: 0x7ed321,
sad: 0x4a90e2,
angry: 0xd0021b,
neutral: 0xffffff
};
var tint = moodTints[node.mood] !== undefined ? moodTints[node.mood] : 0xffffff;
portraitNode.tint = tint;
} else {
portraitNode.tint = 0xffffff;
}
// Remove any previous related character portrait
if (game.relatedPortraitNode) {
game.removeChild(game.relatedPortraitNode);
game.relatedPortraitNode = null;
}
// If the node is about a character other than Mike, show that character next to Mike
if (node.portrait && node.portrait !== "mike" && (node.portrait === "lisa" || node.portrait === "rebecca" || node.portrait === "peter" || node.portrait === "alex")) {
var relatedPortrait = LK.getAsset(node.portrait, {
anchorX: 0.5,
anchorY: 0.5
});
// Place to the right of Mike, with a small gap
relatedPortrait.x = portraitNode.x + portraitNode.width / 2 + relatedPortrait.width / 2 + 40;
relatedPortrait.y = portraitNode.y;
// Mood tint for related portrait
if (node.mood) {
var moodTints = {
happy: 0x7ed321,
sad: 0x4a90e2,
angry: 0xd0021b,
neutral: 0xffffff
};
relatedPortrait.tint = moodTints[node.mood] !== undefined ? moodTints[node.mood] : 0xffffff;
} else {
relatedPortrait.tint = 0xffffff;
}
game.addChild(relatedPortrait);
game.relatedPortraitNode = relatedPortrait;
} else {
if (game.relatedPortraitNode) {
game.removeChild(game.relatedPortraitNode);
game.relatedPortraitNode = null;
}
}
}
// Speaker
if (speakerText) {
speakerText.setText(node.speaker ? node.speaker : '');
}
// Story text
if (storyText) {
// --- Hatırlatma ve Gölgeli Vicdan Mekanizması ---
// 1. Eğer bu node bir regretTrigger içeriyorsa ve geçmişte ilgili regretLabel ile bir seçim yapıldıysa, iç ses/rüya olarak göster
if (node.regretTrigger && pastChoices.indexOf(node.regretTrigger) !== -1) {
// Vicdan sahnesi: iç ses veya rüya efektiyle göster
var regretTexts = {
"lied": "Gece rüyanda, Lisa'nın sana 'Bana neden yalan söyledin?' dediğini duyuyorsun. Vicdanın sızlıyor.",
"betrayed_lisa": "Bir an için Lisa'nın gözlerinde hayal kırıklığını görüyorsun. İç sesin: 'Ona ihanet ettin.'",
"ignored_peter": "Peter'ın üzgün bakışları aklından çıkmıyor. İç sesin: 'Dostunu yalnız bıraktın.'"
};
var regretText = regretTexts[node.regretTrigger] || "Geçmişteki bir kararın gölgesi seni rahatsız ediyor.";
storyText.setText(regretText + "\n\n(" + node.text + ")");
// Fade efekt: metni kısa süreliğine yarı saydam göster
storyText.alpha = 0.5;
tween(storyText, {
alpha: 1
}, {
duration: 1200,
easing: tween.easeOut
});
} else if (
// Yalancı Hafıza: Eğer honest bar düşükse ve geçmişte yalan söylendiyse, yanlış hatırlama metni göster
bar_honest <= 30 && pastChoices.indexOf("lied") !== -1 && (node.id === "lisa_breakfast_mid" || node.id === "lisa_breakfast_high" || node.id === "lisa_breakfast_low")) {
// Yalancı hafıza: Oyuncuya yanlış bilgi ver
storyText.setText("Mike sanki o gün Lisa'ya doğruyu söylediğini hatırlıyordu... ama aslında yalan söylemişti.\n\n(" + node.text + ")");
storyText.alpha = 0.7;
tween(storyText, {
alpha: 1
}, {
duration: 1200,
easing: tween.easeOut
});
} else if (node.id === "lisa_breakfast_mid" && pastChoices.indexOf("lied") !== -1) {
storyText.setText("Lisa sana biraz mesafeli bakıyor. Geçmişteki yalanların etkisi sürüyor.");
} else {
storyText.setText(node.text);
}
}
// Option buttons
// --- Timed Choice Mechanism: If node.timedChoice is set, start a timer and auto-select if no choice is made ---
var timedChoiceTimeout = null;
var timedChoiceBar = null;
if (node.options && node.options.length > 0) {
// If previous timer exists, clear it
if (game._timedChoiceTimeout) {
LK.clearTimeout(game._timedChoiceTimeout);
game._timedChoiceTimeout = null;
}
if (game._timedChoiceBar) {
game.removeChild(game._timedChoiceBar);
game._timedChoiceBar = null;
}
// If this node is a crisis/timed scene, e.g. node.timedChoice: { seconds: 5, default: 1 }
var isTimed = node.timedChoice && typeof node.timedChoice.seconds === "number";
var timedSeconds = isTimed ? node.timedChoice.seconds : 0;
var timedDefault = isTimed ? typeof node.timedChoice["default"] === "number" ? node.timedChoice["default"] : 0 : 0;
var timedStart = Date.now();
var timedBarWidth = 900;
var timedBarHeight = 24;
var timedBarY = 1700 + node.options.length * 180 + 40;
// Option button creation
for (var i = 0; i < node.options.length; i++) {
var opt = node.options[i];
// --- Requirements check ---
var meetsReq = true;
if (opt.requirements) {
for (var key in opt.requirements) {
var val = opt.requirements[key];
// Check current bar/relationship value
var current = 0;
if (key === 'lisa') current = rel_lisa;else if (key === 'rebecca') current = rel_rebecca;else if (key === 'peter') current = rel_peter;else if (key === 'alex') current = rel_alex;else if (key === 'happy') current = bar_happy;else if (key === 'honest') current = bar_honest;else if (key === 'lust') current = bar_lust;else if (key === 'betray') current = bar_betray;
if (current < val) {
meetsReq = false;
break;
}
}
}
var btn = new OptionButton();
// --- Bilinmeyen Seçim Sistemi: option'a hiddenByBar eklendiyse ve bar yeterli değilse gizle ---
var showAsHidden = false;
if (opt.hiddenByBar) {
// hiddenByBar: { key: 'honest', min: 60 } veya { key: 'betray', min: 40 }
var barKey = opt.hiddenByBar.key;
var minVal = typeof opt.hiddenByBar.min === "number" ? opt.hiddenByBar.min : 0;
var currentVal = 0;
if (barKey === 'lisa') currentVal = rel_lisa;else if (barKey === 'rebecca') currentVal = rel_rebecca;else if (barKey === 'peter') currentVal = rel_peter;else if (barKey === 'alex') currentVal = rel_alex;else if (barKey === 'happy') currentVal = bar_happy;else if (barKey === 'honest') currentVal = bar_honest;else if (barKey === 'lust') currentVal = bar_lust;else if (barKey === 'betray') currentVal = bar_betray;
if (currentVal < minVal) showAsHidden = true;
}
if (showAsHidden) {
btn.setText("???");
btn.bg.tint = 0x888888;
btn.text.style.fill = '#bbbbbb';
btn.setCallback(function () {}); // No-op
} else {
btn.setText(opt.text);
// If requirements not met, disable and gray out
if (!meetsReq) {
btn.bg.tint = 0x888888;
btn.text.style.fill = '#bbbbbb';
btn.setCallback(function () {}); // No-op
} else {
btn.setCallback(function (opt, btnIdx) {
return function () {
// If a timed choice is running, clear the timer and bar
if (game._timedChoiceTimeout) {
LK.clearTimeout(game._timedChoiceTimeout);
game._timedChoiceTimeout = null;
}
if (game._timedChoiceBar) {
game.removeChild(game._timedChoiceBar);
game._timedChoiceBar = null;
}
applyEffects(opt.effects, opt.meta);
// Her zaman random bir sonraki soru seç, ama bar değerine göre uygun versiyonu seç
var available = [];
for (var j = 0; j < story.length; j++) {
if (story[j].options && story[j].options.length > 0) available.push(j);
}
if (available.length > 0) {
// getNextNode fonksiyonu ile uygun node'u seç
var nextIdx = getNextNode();
currentNode = nextIdx;
showStoryNode(currentNode);
} else {
// Oyun bitti, son ekranı göster
showEnding();
}
};
}(opt, i));
}
}
btn.x = 2048 / 2;
btn.y = 1700 + i * 180;
game.addChild(btn);
optionButtons.push(btn);
}
// If this is a timed choice, show a timer bar and auto-select after timeout
if (isTimed) {
// Create a timer bar (background and fill)
var barBg = LK.getAsset('bar_bg', {
anchorX: 0.5,
anchorY: 0.5
});
barBg.width = timedBarWidth;
barBg.height = timedBarHeight;
barBg.x = 2048 / 2;
barBg.y = timedBarY;
var barFill = LK.getAsset('bar_fill_betray', {
anchorX: 0.5,
anchorY: 0.5
});
barFill.width = timedBarWidth;
barFill.height = timedBarHeight;
barFill.x = 2048 / 2;
barFill.y = timedBarY;
// Add to game
game.addChild(barBg);
game.addChild(barFill);
// Store for cleanup
game._timedChoiceBar = barBg;
game._timedChoiceBarFill = barFill;
// Animate the bar fill
var updateTimerBar = function updateTimerBar() {
var elapsed = (Date.now() - timedStart) / 1000;
var remain = Math.max(0, timedSeconds - elapsed);
var ratio = remain / timedSeconds;
barFill.width = timedBarWidth * ratio;
if (ratio <= 0) {
barFill.width = 0;
}
};
// Per-frame update for timer bar
var timerBarInterval = LK.setInterval(function () {
if (!game._timedChoiceBarFill) {
LK.clearInterval(timerBarInterval);
return;
}
updateTimerBar();
}, 50);
// Timeout: auto-select default option
game._timedChoiceTimeout = LK.setTimeout(function () {
// Only trigger if still on this node
if (game._timedChoiceBar) {
// Simulate click on default option
if (optionButtons[timedDefault] && typeof optionButtons[timedDefault].down === "function") {
optionButtons[timedDefault].down();
}
// Clean up timer bar
if (game._timedChoiceBar) {
game.removeChild(game._timedChoiceBar);
game._timedChoiceBar = null;
}
if (game._timedChoiceBarFill) {
game.removeChild(game._timedChoiceBarFill);
game._timedChoiceBarFill = null;
}
LK.clearInterval(timerBarInterval);
game._timedChoiceTimeout = null;
}
}, timedSeconds * 1000);
}
}
}
function applyEffects(effects, meta) {
if (!effects) return;
// --- Memory mechanic: record important choices ---
// Example: If the player kisses Lisa, lies to Rebecca, etc.
// We'll record meta.memoryLabel if present, otherwise try to infer from meta/type
if (meta && meta.memoryLabel) {
pastChoices.push(meta.memoryLabel);
} else if (meta && meta.type === "lie") {
pastChoices.push("lied");
// Regretful: lying is a regret
} else if (meta && meta.type === "truth") {
pastChoices.push("told_truth");
}
// Regretful: betray Lisa
if (typeof effects.lisa === 'number' && effects.lisa < 0 && typeof effects.betray === 'number' && effects.betray > 0) {
pastChoices.push("betrayed_lisa");
}
// Regretful: ignore Peter
if (typeof effects.peter === 'number' && effects.peter < 0 && meta && meta.ignoreRegret) {
pastChoices.push("ignored_peter");
}
// Sadece yüzde 1 artıp azalsın
if (typeof effects.lisa === 'number') rel_lisa = Math.max(0, Math.min(100, rel_lisa + (effects.lisa > 0 ? 1 : effects.lisa < 0 ? -1 : 0)));
if (typeof effects.rebecca === 'number') rel_rebecca = Math.max(0, Math.min(100, rel_rebecca + (effects.rebecca > 0 ? 1 : effects.rebecca < 0 ? -1 : 0)));
if (typeof effects.peter === 'number') rel_peter = Math.max(0, Math.min(100, rel_peter + (effects.peter > 0 ? 1 : effects.peter < 0 ? -1 : 0)));
if (typeof effects.alex === 'number') rel_alex = Math.max(0, Math.min(100, rel_alex + (effects.alex > 0 ? 1 : effects.alex < 0 ? -1 : 0)));
if (typeof effects.happy === 'number') {
bar_happy = Math.max(0, Math.min(100, bar_happy + (effects.happy > 0 ? 1 : effects.happy < 0 ? -1 : 0)));
if (typeof villaUnlocked !== "undefined" && villaUnlocked && bar_happy < 80) {
bar_happy = 80;
}
}
if (typeof effects.honest === 'number') bar_honest = Math.max(0, Math.min(100, bar_honest + (effects.honest > 0 ? 1 : effects.honest < 0 ? -1 : 0)));
if (typeof effects.lust === 'number') bar_lust = Math.max(0, Math.min(100, bar_lust + (effects.lust > 0 ? 1 : effects.lust < 0 ? -1 : 0)));
if (typeof effects.betray === 'number') bar_betray = Math.max(0, Math.min(100, bar_betray + (effects.betray > 0 ? 1 : effects.betray < 0 ? -1 : 0)));
// --- Villa davet event: karakterle ilişkiyi %15 artır (etki zaten effects ile geliyor, ama burada ek bir kontrol de eklenebilir) ---
if (meta && meta.type === "villa_invite" && typeof meta.character === "string") {
if (meta.character === "lisa") rel_lisa = Math.min(100, rel_lisa + 15);
if (meta.character === "rebecca") rel_rebecca = Math.min(100, rel_rebecca + 15);
if (meta.character === "peter") rel_peter = Math.min(100, rel_peter + 15);
if (meta.character === "alex") rel_alex = Math.min(100, rel_alex + 15);
}
// --- Giselle para harcama ve hamilelik ---
if (meta && meta.type === "giselle_spend" && typeof meta.money === "number") {
mikeMoney = Math.max(0, mikeMoney + meta.money);
}
// --- Whiskey para harcama ---
if (meta && meta.type === "whiskey_spend" && typeof meta.money === "number") {
mikeMoney = Math.max(0, mikeMoney + meta.money);
}
if (meta && meta.type === "giselle_baby" && giselleUnlocked && !gisellePregnant) {
if (Math.random() < 0.3) {
gisellePregnant = true;
// Bebek doğumu bir sonraki günlerde gerçekleşecek
}
}
// --- Shadow bar logic: increase/decrease based on hidden triggers ---
// Betrayal, repeated lies, or negative choices increase shadow bar
if (meta && meta.type === "lie" || typeof effects.betray === 'number' && effects.betray > 0) {
bar_shadow = Math.max(0, Math.min(100, bar_shadow + 5));
}
// If player is honest or makes a positive choice, shadow bar may decrease
if (meta && meta.type === "truth" || typeof effects.honest === 'number' && effects.honest > 0) {
bar_shadow = Math.max(0, bar_shadow - 2);
}
// If player ignores Peter or Lisa (meta.ignoreRegret), shadow bar increases
if (meta && meta.ignoreRegret) {
bar_shadow = Math.max(0, Math.min(100, bar_shadow + 3));
}
// --- Honest bar penalty for repeated lies ---
if (meta && meta.type === "lie") {
// Lying reduces honest bar by 2 (or 1 if already low)
bar_honest = Math.max(0, bar_honest - (bar_honest > 10 ? 2 : 1));
}
// --- Relationship Cross Effects ---
applyCrossEffects(effects, meta);
updateBars();
// --- Turn-based trigger system ---
// Increase turn count on every choice
turnCount++;
// --- Ava: Advance time every 2 turns (1 day = 2 questions) ---
if (turnCount % 2 === 0) {
dayCount++;
// Mike maaş alır
mikeMoney += mikeSalary;
// Alex ile ilişki > 70 ise maaş +50
if (rel_alex > 70) {
mikeSalary += 50;
}
// Alex ile ilişki < 30 ise maaş -20
if (rel_alex < 30) {
mikeSalary = Math.max(0, mikeSalary - 20);
}
// Peter ile ilişki > 70 ise mutluluk +1
if (rel_peter > 70) {
bar_happy = Math.min(100, bar_happy + 1);
}
// Lisa hamile ise doğum (her gün %10 ihtimal)
if (lisaPregnant && Math.random() < 0.1) {
mikeBabyCount++;
lisaPregnant = false;
}
// Rebecca hamile ise doğum (her gün %10 ihtimal)
if (rebeccaPregnant && Math.random() < 0.1) {
mikeBabyCount++;
rebeccaPregnant = false;
}
// Giselle hamile ise doğum (her gün %10 ihtimal)
if (gisellePregnant && Math.random() < 0.1) {
mikeBabyCount++;
gisellePregnant = false;
}
// Save to storage
storage.mikeMoney = mikeMoney;
storage.mikeSalary = mikeSalary;
storage.mikeBabyCount = mikeBabyCount;
storage.dayCount = dayCount;
storage.lisaPregnant = lisaPregnant;
storage.rebeccaPregnant = rebeccaPregnant;
// Update UI
updateBars();
}
// --- Dış Etki Mekanizması: Lust bar 3 tur boyunca yüksekse otomatik karar ---
// Son 3 turdaki lust bar değerlerini takip et
if (!flags.lustHistory) flags.lustHistory = [];
flags.lustHistory.push(bar_lust);
if (flags.lustHistory.length > 3) flags.lustHistory.shift();
// Eğer son 3 turda lust barı 70 ve üzeriyse, otomatik bir karar tetiklenir (ör: irade kaybı)
if (flags.lustHistory.length === 3 && flags.lustHistory[0] >= 70 && flags.lustHistory[1] >= 70 && flags.lustHistory[2] >= 70 && !flags.lustAutoDecision) {
flags.lustAutoDecision = true;
// Oyuncunun kontrolü dışında bir olay: Rebecca ile yakınlaşma
if (storyText) {
storyText.setText("Mike, arzularına yenik düşüyor ve Rebecca'ya karşı koyamıyor. (Dış etki: İrade kaybı)");
storyText.alpha = 0.7;
tween(storyText, {
alpha: 1
}, {
duration: 1200,
easing: tween.easeOut
});
}
// Bar ve ilişkilerde otomatik değişiklikler
rel_rebecca = Math.min(100, rel_rebecca + 5);
bar_lust = Math.min(100, bar_lust + 5);
bar_betray = Math.min(100, bar_betray + 5);
updateBars();
// Sonraki node'a otomatik geçiş (Rebecca ile ilgili bir sahneye öncelik ver)
var rebeccaIdx = -1;
for (var i = 0; i < story.length; i++) {
if (story[i].portrait === "rebecca" && story[i].options && story[i].options.length > 0) {
rebeccaIdx = i;
break;
}
}
if (rebeccaIdx !== -1) {
currentNode = rebeccaIdx;
LK.setTimeout(function () {
showStoryNode(currentNode);
}, 1800);
return;
}
}
// Zamana bağlı özel rüya sahnesi tetikleyici örneği
if (turnCount > 15 && bar_lust > 60 && !flags["specialDreamTriggered"]) {
flags["specialDreamTriggered"] = true;
showEnding("Mike, arzularının peşinden sürüklendiği özel bir rüya görüyor. (Zamana bağlı özel sahne)");
return;
}
// --- Bar-based flag system ---
// Example: if betrayal bar reaches 80 or more, set betrayalUnlocked flag
if (bar_betray >= 80) {
flags["betrayalUnlocked"] = true;
}
if (bar_honest >= 90) {
flags["honestyMaster"] = true;
}
if (bar_lust >= 90) {
flags["lustHigh"] = true;
}
if (bar_happy >= 90) {
flags["happinessPeak"] = true;
}
if (rel_lisa >= 90) {
flags["lisaBond"] = true;
}
if (rel_rebecca >= 90) {
flags["rebeccaBond"] = true;
}
if (rel_peter >= 90) {
flags["peterBond"] = true;
}
if (rel_alex >= 90) {
flags["alexBond"] = true;
}
// --- Shadow bar event triggers (hidden, unexpected events) ---
if (!flags.shadow30 && bar_shadow >= 30) {
flags.shadow30 = true;
// Ani içsel monolog: Mike'ın öfke patlaması
if (storyText) {
storyText.setText("Mike'ın içinde bir öfke kabarıyor. (İç ses: 'Bazen her şeyi yakıp yıkmak istiyorum...')\n\n" + (storyText.text || ""));
storyText.alpha = 0.7;
tween(storyText, {
alpha: 1
}, {
duration: 1000,
easing: tween.easeOut
});
}
}
if (!flags.shadow60 && bar_shadow >= 60) {
flags.shadow60 = true;
// Mike'ın beklenmedik bir şekilde bağırması (oyuncuya yansır)
if (storyText) {
storyText.setText("Mike aniden bağırıyor: 'YETER ARTIK!'\n\n" + (storyText.text || ""));
storyText.alpha = 0.7;
tween(storyText, {
alpha: 1
}, {
duration: 1000,
easing: tween.easeOut
});
}
// Portrait kırmızıya döner, kısa süreliğine
if (portraitNode) {
var oldTint = portraitNode.tint;
portraitNode.tint = 0xd0021b;
tween(portraitNode, {
tint: oldTint
}, {
duration: 1200,
easing: tween.easeOut
});
}
}
if (!flags.shadow90 && bar_shadow >= 90) {
flags.shadow90 = true;
// Mike'ın içsel çöküşü: iç ses, portre fade out
if (storyText) {
storyText.setText("Mike'ın zihni karanlığa gömülüyor. (İç ses: 'Artık kendimi tanıyamıyorum...')\n\n" + (storyText.text || ""));
storyText.alpha = 0.5;
tween(storyText, {
alpha: 1
}, {
duration: 1500,
easing: tween.easeOut
});
}
if (portraitNode) {
tween(portraitNode, {
alpha: 0.2
}, {
duration: 1500,
easing: tween.easeOut
});
}
}
// Check for fail/win conditions
if (bar_happy <= 0) {
showEnding('Mutluluk sıfırlandı. Mike depresyona girdi.');
return;
}
if (bar_honest <= 0) {
showEnding('Dürüstlük sıfırlandı. Mike yalanlarla dolu bir hayata saplandı.');
return;
}
if (bar_lust <= 0) {
showEnding('Şehvet sıfırlandı. Mike hayattan keyif alamıyor.');
return;
}
if (bar_betray >= 100) {
showEnding('İhanet %100 oldu. Mike ilişkilerini kaybetti.');
return;
}
}
// İlişki çaprazlama mekanizması: Lisa ile yakınlık artınca Rebecca kıskanır, Rebecca ile yakınlık artınca Lisa üzülür, vs.
function applyCrossEffects(effects, meta) {
// Lisa ile yakınlık artarsa Rebecca'nın ilişkisi biraz azalır (kıskançlık)
if (typeof effects.lisa === 'number' && effects.lisa > 0) {
// Lisa ile +1 yakınlık, Rebecca -1
rel_rebecca = Math.max(0, rel_rebecca - 1);
}
// Rebecca ile yakınlık artarsa Lisa'nın ilişkisi biraz azalır (kıskançlık)
if (typeof effects.rebecca === 'number' && effects.rebecca > 0) {
rel_lisa = Math.max(0, rel_lisa - 1);
}
// Lisa ile yakınlık azalırsa Rebecca biraz mutlu olur (rekabet)
if (typeof effects.lisa === 'number' && effects.lisa < 0) {
rel_rebecca = Math.min(100, rel_rebecca + 1);
}
// Rebecca ile yakınlık azalırsa Lisa biraz mutlu olur (rekabet)
if (typeof effects.rebecca === 'number' && effects.rebecca < 0) {
rel_lisa = Math.min(100, rel_lisa + 1);
}
// Betray (ihanet) barı artarsa Lisa ve Rebecca'nın ilişkisi biraz azalır
if (typeof effects.betray === 'number' && effects.betray > 0) {
rel_lisa = Math.max(0, rel_lisa - 1);
rel_rebecca = Math.max(0, rel_rebecca - 1);
}
// Lust barı çok artarsa (ör: Rebecca ile), Lisa'nın ilişkisi biraz azalır
if (typeof effects.lust === 'number' && effects.lust > 0) {
rel_lisa = Math.max(0, rel_lisa - 1);
}
// Happy barı çok azalırsa, tüm ilişkiler biraz azalır
if (typeof effects.happy === 'number' && effects.happy < 0) {
rel_lisa = Math.max(0, rel_lisa - 1);
rel_rebecca = Math.max(0, rel_rebecca - 1);
rel_peter = Math.max(0, rel_peter - 1);
rel_alex = Math.max(0, rel_alex - 1);
}
}
function showEnding(msg) {
// Remove option buttons
for (var i = 0; i < optionButtons.length; i++) {
game.removeChild(optionButtons[i]);
}
optionButtons = [];
// --- Animated, bar-specific game over ---
// Determine which bar triggered game over
var endingType = null;
if (typeof msg === "string") {
if (msg.indexOf("Mutluluk") !== -1) endingType = "happy";else if (msg.indexOf("Dürüstlük") !== -1) endingType = "honest";else if (msg.indexOf("Şehvet") !== -1) endingType = "lust";else if (msg.indexOf("İhanet") !== -1) endingType = "betray";
}
// Default: Mike portrait
var portraitKey = "mike";
var endingText = msg;
var mood = "sad";
var crossX = null;
// Custom portrait and text for each bar
if (endingType === "betray") {
// Mike gözaltına alınıyor
portraitKey = "mike";
endingText = "SON: Mike ihanetin bedelini ödedi ve gözaltına alındı.\n\nYeniden başlamak için ekrana dokunun.";
mood = "angry";
crossX = true;
} else if (endingType === "lust") {
// Lisa uzaklaşıyor
portraitKey = "lisa";
endingText = "SON: Lisa, Mike'ın tutkularının sönmesiyle uzaklaştı.\n\nYeniden başlamak için ekrana dokunun.";
mood = "sad";
crossX = true;
} else if (endingType === "happy") {
// Mike depresyona giriyor
portraitKey = "mike";
endingText = "SON: Mike mutluluğunu kaybetti ve depresyona girdi.\n\nYeniden başlamak için ekrana dokunun.";
mood = "sad";
crossX = false;
} else if (endingType === "honest") {
// Mike yalanlarla dolu bir hayata saplandı
portraitKey = "mike";
endingText = "SON: Mike dürüstlüğünü kaybetti, yalanlarla dolu bir hayata saplandı.\n\nYeniden başlamak için ekrana dokunun.";
mood = "angry";
crossX = true;
}
// Show ending text
if (storyText) {
if (endingText) {
storyText.setText(endingText);
} else if (msg) {
storyText.setText('SON: ' + msg + '\n\nYeniden başlamak için ekrana dokunun.');
} else {
storyText.setText('SON: Mike’ın hikayesi burada bitiyor.\n\nYeniden başlamak için ekrana dokunun.');
}
}
// Remove speaker
if (speakerText) speakerText.setText('');
// Animate portrait: change to relevant character, mood tint, fade out, and cross if needed
if (portraitNode) {
// Change portrait image
if (LK.getAsset(portraitKey, {})) {
portraitNode.texture = LK.getAsset(portraitKey, {}).texture;
}
// Mood-based tint
var moodTints = {
happy: 0x7ed321,
sad: 0x4a90e2,
angry: 0xd0021b,
neutral: 0xffffff
};
var tint = moodTints[mood] !== undefined ? moodTints[mood] : 0xffffff;
portraitNode.tint = tint;
// Animate: fade out after 1.2s
tween(portraitNode, {
alpha: 0.3
}, {
duration: 1200,
easing: tween.easeOut
});
// If crossX, show a red cross over portrait
if (crossX) {
// Create a red cross using two rectangles (since we can't draw lines)
var cross1 = LK.getAsset('bar_fill_betray', {
anchorX: 0.5,
anchorY: 0.5
});
var cross2 = LK.getAsset('bar_fill_betray', {
anchorX: 0.5,
anchorY: 0.5
});
// Set size and rotation for cross
var size = Math.max(portraitNode.width, portraitNode.height) * 0.9;
cross1.width = size;
cross1.height = 24;
cross2.width = size;
cross2.height = 24;
cross1.rotation = Math.PI / 4;
cross2.rotation = -Math.PI / 4;
cross1.alpha = 0.85;
cross2.alpha = 0.85;
cross1.x = portraitNode.x;
cross1.y = portraitNode.y;
cross2.x = portraitNode.x;
cross2.y = portraitNode.y;
cross1.zIndex = 100;
cross2.zIndex = 100;
game.addChild(cross1);
game.addChild(cross2);
// Animate cross: fade in, then fade out after 1.2s
cross1.alpha = 0;
cross2.alpha = 0;
tween(cross1, {
alpha: 0.85
}, {
duration: 400,
easing: tween.easeOut
});
tween(cross2, {
alpha: 0.85
}, {
duration: 400,
easing: tween.easeOut
});
// Fade out after 1.2s
LK.setTimeout(function () {
tween(cross1, {
alpha: 0
}, {
duration: 600,
easing: tween.easeOut
});
tween(cross2, {
alpha: 0
}, {
duration: 600,
easing: tween.easeOut
});
LK.setTimeout(function () {
game.removeChild(cross1);
game.removeChild(cross2);
}, 700);
}, 1200);
}
}
// Add restart handler
game.down = function (x, y, obj) {
game.down = null;
restartGame();
};
}
function restartGame() {
resetGameState();
updateBars();
showStoryNode(currentNode);
// Remove restart handler
game.down = null;
}
// --- Start Game ---
resetGameState();
createUI();
updateBars();
showStoryNode(currentNode);
// --- No dragging or move events needed for this game ---
// --- Game update (not used, but required for LK) ---
game.update = function () {
// No per-frame logic needed
};
Boss Man head. In-Game asset. 2d. High contrast. No shadows
Housewife Head. In-Game asset. 2d. High contrast. No shadows
Blonde Handsome Man. In-Game asset. 2d. High contrast. No shadows
handsome, black hair, goat beard man head. In-Game asset. 2d. High contrast. No shadows
sexy ginger woman head In-Game asset. 2d. High contrast. No shadows
briefcase. In-Game asset. 2d. High contrast. No shadows
soccer ball. In-Game asset. 2d. High contrast. No shadows
flame heart. In-Game asset. 2d. High contrast. No shadows
motorcycle. In-Game asset. 2d. High contrast. No shadows
limuzin. In-Game asset. 2d. High contrast. No shadows
Black popart background. Only dark colors. Lots of pop art reference In-Game asset. 2d. High contrast. No shadows
Sexy beautiful French Woman face In-Game asset. 2d. High contrast. No shadows
German Shepard face. realistic In-Game asset. 2d. High contrast. No shadows
realistic villa. In-Game asset. 2d. High contrast. No shadows