diff --git a/src/com/lilithsthrone/game/character/GameCharacter.java b/src/com/lilithsthrone/game/character/GameCharacter.java
index 3b0d1434cd..36f147ba1a 100644
--- a/src/com/lilithsthrone/game/character/GameCharacter.java
+++ b/src/com/lilithsthrone/game/character/GameCharacter.java
@@ -291,6 +291,8 @@
import com.lilithsthrone.utils.XMLSaving;
import com.lilithsthrone.utils.colours.Colour;
import com.lilithsthrone.utils.colours.PresetColour;
+import com.lilithsthrone.utils.time.AstronomicalSign;
+import com.lilithsthrone.utils.time.ChineseZodiac;
import com.lilithsthrone.world.AbstractWorldType;
import com.lilithsthrone.world.Cell;
import com.lilithsthrone.world.World;
@@ -341,7 +343,7 @@ public abstract class GameCharacter implements XMLSaving {
protected LocalDateTime birthday;
protected int ageAppearanceDifference;
protected int ageAppearanceAbsolute;
-
+
protected Occupation occupation;
protected Set
Set parserTarget: " + loadedParserTarget);
}
-
+
// Name:
Element nameElement = (Element) element.getElementsByTagName("name").item(0);
String nameElementValue = nameElement.getAttribute("value");
@@ -1623,7 +1625,7 @@ public static void loadGameCharacterVariablesFromXML(GameCharacter character, St
character.setAgeAppearanceAbsolute(Integer.valueOf(((Element)element.getElementsByTagName("ageAppearanceAbsolute").item(0)).getAttribute("value")));
Main.game.getCharacterUtils().appendToImportLog(log, "
Set ageAppearanceAbsolute: " + Integer.valueOf(((Element)element.getElementsByTagName("ageAppearanceAbsolute").item(0)).getAttribute("value")));
}
-
+
// Birthday:
try {
int day = Integer.valueOf(((Element)element.getElementsByTagName("dayOfBirth").item(0)).getAttribute("value"));
@@ -1940,7 +1942,7 @@ public static void loadGameCharacterVariablesFromXML(GameCharacter character, St
}
}
}
-
+
// Knows area map:
try {
if(Main.isVersionOlderThan(version, "0.2.10")) {
@@ -2849,7 +2851,7 @@ public static void loadGameCharacterVariablesFromXML(GameCharacter character, St
ex.printStackTrace();
}
}
-
+
for(int i=0; i<((Element) slaveryElement.getElementsByTagName("slavesOwned").item(0)).getElementsByTagName("slave").getLength(); i++){
Element e = ((Element)slaveryElement.getElementsByTagName("slave").item(i));
@@ -3453,7 +3455,7 @@ public static void loadGameCharacterVariablesFromXML(GameCharacter character, St
character.setAgeAppearanceAbsolute(character.getAppearsAsAgeValue());
}
}
-
+
character.calculateStatusEffects(0);
character.recalculateSleepHours();
for(String moveId : movesToEquip) { // Equip moves after status effects have been calculated:
@@ -3490,7 +3492,7 @@ public void loadImages(boolean forceReload) {
artworkList.clear();
artworkFolderName = folder;
}
-
+
if(!folder.isEmpty()) {
if(!this.isUnique() || this.isPlayer()) {
File f = new File("data/images/"+Main.game.getId()+"/characters/" + folder);
@@ -3574,7 +3576,7 @@ public boolean isDoll() {
}
return getBody().isDoll();
}
-
+
/**
* @return true if this character is a doll, is working as a statue at the current game.getHourOfDay()
, and has not been ordered to stop acting as a statue, determined from SlaveDialogue.isDollStatueInterrupted()
*/
@@ -3584,7 +3586,7 @@ public boolean isDollStatue() {
&& getSlaveJob(Main.game.getHourOfDay())==SlaveJob.DOLL_STATUE
&& this.isAtWork();
}
-
+
public boolean isRaceConcealed() {
return raceConcealed;
}
@@ -3610,7 +3612,7 @@ public String getParserTarget() {
public void setParserTarget(String parserTarget) {
this.parserTarget = parserTarget;
}
-
+
public String getMapIcon() {
if(isRaceConcealed()) {
return SVGImages.SVG_IMAGE_PROVIDER.getRaceUnknown();
@@ -3722,7 +3724,7 @@ public String getCharacterInformationScreen(boolean includePerkTree) {
+ this.getDescription());
boolean incubated = this.getIncubator()!=null;
-
+
boolean append = false;
if(Main.game.getPlayer().getId().equals(this.getMotherId())) {
append = true;
@@ -3731,12 +3733,12 @@ public String getCharacterInformationScreen(boolean includePerkTree) {
?" After being incubated by "+(this.getIncubator().isPlayer()?"yourself":this.getIncubator().getName())+", [npc.she] [npc.was] born"
:" You gave birth to [npc.herHim]")
+" on the "+this.getBirthdayString()));
-
+
} else if(this.isPlayer() || (this.isPlayerKnowsName() && (this.getAffection(Main.game.getPlayer())>=AffectionLevel.POSITIVE_ONE_FRIENDLY.getMinimumValue() || this.isSlave()))) {
append = true;
if(this.isDoll()) {
infoScreenSB.append(UtilText.parse(this, " [npc.She] [npc.was] created on the "+this.getBirthdayString()));
-
+
} else {
infoScreenSB.append(UtilText.parse(this,
(incubated
@@ -3759,14 +3761,21 @@ public String getCharacterInformationScreen(boolean includePerkTree) {
:"")
+ " makes [npc.herHim] "+Util.intToString(this.getAgeValue())+" years old."));
}
-
+
} else {
infoScreenSB.append(".");
}
}
+ AstronomicalSign astronomicalSign = AstronomicalSign.getSignFromDate(this.getBirthday());
+ infoScreenSB.append(UtilText.parse(this,
+ " [npc.HerPos] astronomical sign is "
+ +astronomicalSign.getName()
+ +" ("+astronomicalSign.getHtmlDisplay()+")"
+ +" and [npc.herPos] chinese zodiac animal is "
+ +ChineseZodiac.getSignFromDate(this.getBirthday()).getName()+"."));
infoScreenSB.append("
");
String relationships = this.getRelationshipStrTo(Main.game.getPlayer());
@@ -3798,12 +3807,12 @@ public String getCharacterInformationScreen(boolean includePerkTree) {
}
}
}
-
+
if(relationshipsSB.length()>0) {
infoScreenSB.append(relationshipsSB.toString());
infoScreenSB.append("
");
}
-
+
int affection = (int)this.getAffection(Main.game.getPlayer());
infoScreenSB.append(AffectionLevel.getDescription(this, Main.game.getPlayer(), true)+" ("+(affection>0?"+":"")+affection+")");
@@ -3849,7 +3858,7 @@ public String getCharacterInformationScreen(boolean includePerkTree) {
}
}
infoScreenSB.append("
"); int i=0; @@ -4254,7 +4263,7 @@ protected void additionalBodySetup(Gender gender, AbstractRacialBody startingRac sexualOrientation = startingRace.getSexualOrientation(gender); initPerkTreeAndBackgroundPerks(); - + // This is the same as the age setting in CharacterUtil.randomiseBody() if(Main.game.isStarted() && startingSpeciesType.isDoesNotAge() && this.getAgeAppearanceAbsolute()==0) { this.setAgeAppearanceAbsolute(Math.min(this.getAgeValue(), 18+Util.random.nextInt(19))); // Range of real age to 36 @@ -4523,7 +4532,7 @@ public LocalDateTime getBirthday() { public void setBirthday(LocalDateTime birthday) { this.birthday = birthday; } - + public void setAge(int years) { this.birthday = LocalDateTime.of(Main.game.getStartingDate().getYear()-(years-MINIMUM_AGE), birthday.getMonth(), (birthday.getMonth()==Month.FEBRUARY&&birthday.getDayOfMonth()==29?28:birthday.getDayOfMonth()), 12, 0); } @@ -4560,9 +4569,9 @@ public int getAgeDifferenceUpperLimit() { } return 10; } - + // Age appearance based on difference: - + public int getAgeAppearanceDifference() { return ageAppearanceDifference; } @@ -4586,11 +4595,11 @@ public void setAgeAppearanceDifferenceToAppearAsAge(int targetedAge) { } // Age appearance based on an absolute value: - + public int getAgeAppearanceAbsolute() { return ageAppearanceAbsolute; } - + /** * This age appearance is an absolute value and does not advance based on the passage of time. * This character will always appear to be this age no matter the date. @@ -4601,13 +4610,13 @@ public int getAgeAppearanceAbsolute() { public void setAgeAppearanceAbsolute(int ageAppearanceAbsolute) { this.ageAppearanceAbsolute = ageAppearanceAbsolute; } - + public void incrementAgeAppearanceAbsolute(int increment) { setAgeAppearanceAbsolute(getAgeAppearanceAbsolute() + increment); } - + // Birthdays: - + public Month getBirthMonth() { return birthday.getMonth(); } @@ -4872,15 +4881,15 @@ public boolean isAbleToRefuseSexAsCompanion() { } // Slave stuff: - + public AbstractWorldType getSlaveStationWorldType() { return slaveStationWorldType; } - + public void setSlaveStationWorldType(AbstractWorldType slaveStationWorldType) { this.slaveStationWorldType = slaveStationWorldType; } - + public Vector2i getSlaveStationLocation() { return slaveStationLocation; } @@ -5048,7 +5057,7 @@ public float getBaseStaminaForSlaveJobs() { } return 24f; } - + public float getDailySlaveJobStamina() { float fatigue = getBaseStaminaForSlaveJobs(); for(SlaveJob job : workHours) { @@ -5071,7 +5080,7 @@ public void setSlaveJob24Hours(SlaveJob slaveJob) { workHours[i] = slaveJob; } } - + /** * @return true if this character has a sleeping-related status effect, or if in sex, is immobilised via ImmobilisationType.SLEEP */ @@ -5081,19 +5090,19 @@ public boolean isAsleep() { } return this.hasStatusEffect(StatusEffect.SLEEPING) || this.hasStatusEffect(StatusEffect.SLEEPING_HEAVY); } - + public void wakeUp() { // Joe Biden... Wake up... 9/11... this.removeStatusEffect(StatusEffect.SLEEPING); this.removeStatusEffect(StatusEffect.SLEEPING_HEAVY); } - + public boolean isAffectedBySleepingStatusEffect() { return this.isPlayer() // || (!this.isUnique() || (this.isSlave() && this.getOwner().isPlayer())) // This makes all NPCs sleep, often at very inconvenient times (such as during encounters and combat...) || (this.isSlave() && this.getOwner().isPlayer()) || Main.game.getPlayer().getFriendlyOccupants().contains(this.getId()); } - + public boolean isSleepingAtHour(int hour) { if(!sleepTimesInitialised) { recalculateSleepHours(); @@ -6408,7 +6417,7 @@ public int getExperience() { public void setExperience(int experience) { this.experience = experience; } - + public int getExperienceNeededForNextLevel(int level) { return level * 10; } @@ -6423,12 +6432,12 @@ public String incrementExperience(int increment, boolean withExtraModifiers) { return ""; } if(this.isDoll()) { - return UtilText.parse(this, + return UtilText.parse(this, "
" + "As [npc.nameIsFull] a sex doll, [npc.she] cannot gain experience..." +"
"); } - + int xpIncrement = (int) Math.max(0, increment * (withExtraModifiers&&this.hasTrait(Perk.JOB_WRITER, true)?1.25f:1)); if(withExtraModifiers @@ -7275,7 +7284,7 @@ public String addFetish(AbstractFetish fetish, boolean shortDescription) { + UtilText.parse(this, "[style.colourDisabled(As a sex doll, [npc.nameIsFull] unable to gain fetishes...)]") +""; } - + fetishes.add(fetish); applyFetishGainEffects(fetish); @@ -7658,7 +7667,7 @@ public boolean addStatusEffect(AbstractStatusEffect statusEffect, long lastTimeA getAppliedStatusEffect(statusEffect).setSecondsRemaining(secondsRemaining); return false; } - + if(this.isDoll() && (statusEffect==StatusEffect.PSYCHOACTIVE || statusEffect==StatusEffect.THIRST_QUENCHED @@ -7671,7 +7680,7 @@ public boolean addStatusEffect(AbstractStatusEffect statusEffect, long lastTimeA )) { return false; } - + statusEffects.add(new AppliedStatusEffect(statusEffect, lastTimeAppliedEffect, secondsPassed, secondsRemaining)); // Bonus attributes are not incremented for status effects, as they can vary while a character is under the effects of them. @@ -8527,8 +8536,8 @@ public int calculateSexTypeWeighting(SexType type, GameCharacter target, List[style.italicsMinorBad(Elementals cannot impregnate anyone!)]
[style.italicsDisabled(I will add support for impregnating/being impregnated by elementals later on!)]
" + "[npc.NameIsFull] now an extremely high-quality sex doll, made entirely out of "+colourBasic+" silicone!" @@ -28089,10 +28098,10 @@ public String setBodyMaterial(BodyMaterial type) { + "- [npc.Her] orifices are able to accommodate extremely long penetrations!" + "" + "
"); - + return tfDescription; } - + if(type==BodyMaterial.FLESH) { tfDescription = UtilText.parse(this, "" @@ -28441,7 +28450,7 @@ public String setBodyMaterial(BodyMaterial type) { } // The DOLL changes don't get to here - + body.setBodyMaterial(type); postTransformationCalculation(false); @@ -28798,7 +28807,7 @@ public String removeNippleOrificeModifier(OrificeModifier modifier) { public void clearNippleOrificeModifiers() { body.getBreast().getNipples().getOrificeNipples().clearOrificeModifiers(); } - + // Milk: public FluidMilk getMilk() { return body.getBreast().getMilk(); @@ -29173,7 +29182,7 @@ public String removeNippleCrotchOrificeModifier(OrificeModifier modifier) { public void clearNippleCrotchOrificeModifiers() { body.getBreastCrotch().getNipples().getOrificeNipples().clearOrificeModifiers(); } - + // Milk: public FluidMilk getMilkCrotch() { return body.getBreastCrotch().getMilk(); @@ -29707,7 +29716,7 @@ public String removeFaceOrificeModifier(OrificeModifier modifier) { public void clearFaceOrificeModifiers() { body.getFace().getMouth().getOrificeMouth().clearOrificeModifiers(); } - + // ------------------------------ Genital arrangement: ------------------------------ // @@ -30509,7 +30518,7 @@ public String addUrethraOrificeModifier(OrificeModifier modifier) { public String removeUrethraOrificeModifier(OrificeModifier modifier) { return getCurrentPenis().getOrificeUrethra().removeOrificeModifier(this, modifier); } - + // ------------------------------ Testicles: ------------------------------ // public AbstractBodyCoveringType getTesticlesCovering() { diff --git a/src/com/lilithsthrone/utils/time/AstronomicalSign.java b/src/com/lilithsthrone/utils/time/AstronomicalSign.java new file mode 100644 index 0000000000..6e1512e0ec --- /dev/null +++ b/src/com/lilithsthrone/utils/time/AstronomicalSign.java @@ -0,0 +1,77 @@ +package com.lilithsthrone.utils.time; + +import java.time.LocalDateTime; +import java.time.Month; + +public enum AstronomicalSign { + ARIES("aries", "♈", Month.MARCH, 21, Month.APRIL, 19), + TAURUS("taurus", "♉", Month.APRIL, 20, Month.MAY, 20), + GEMINI("gemini", "♊", Month.MAY, 21, Month.JUNE, 20), + CANCER("cancer", "♋", Month.JUNE, 21, Month.JULY, 22), + LEO("leo", "♌", Month.JULY, 23, Month.AUGUST, 22), + VIRGO("virgo", "♍", Month.AUGUST, 23, Month.SEPTEMBER, 22), + LIBRA("libra", "♎", Month.SEPTEMBER, 23, Month.OCTOBER, 21), + SCORPIO("scorpio", "♏", Month.OCTOBER, 22, Month.NOVEMBER, 21), + SAGITTARIUS("sagittarius", "♐", Month.NOVEMBER, 22, Month.DECEMBER, 21), + CAPRICORN("capricorn", "♑", Month.DECEMBER, 22, Month.JANUARY, 19), + AQUARIUS("aquarius", "♒", Month.JANUARY, 20, Month.FEBRUARY, 18), + PISCES("pisces", "♓", Month.FEBRUARY, 19, Month.MARCH, 20); + + private final String name; + private final String htmlDisplay; + private final Month startMonth; + private final int startDay; + private final Month endMonth; + private final int endDay; + + AstronomicalSign(String name, String htmlDisplay, Month startMonth, int startDay, Month endMonth, int endDay) { + this.name = name; + this.htmlDisplay = htmlDisplay; + this.startMonth = startMonth; + this.startDay = startDay; + this.endMonth = endMonth; + this.endDay = endDay; + } + + public String getName() { + return name; + } + + public String getHtmlDisplay() { + return htmlDisplay; + } + + public Month getStartMonth() { + return startMonth; + } + + public int getStartDay() { + return startDay; + } + + public Month getEndMonth() { + return endMonth; + } + + public int getEndDay() { + return endDay; + } + + @Override + public String toString() { + return getName(); + } + + public static AstronomicalSign getSignFromDate(LocalDateTime dateTime) { + int day = dateTime.getDayOfMonth(); + Month month = dateTime.getMonth(); + + for (AstronomicalSign sign : AstronomicalSign.values()) { + if ((month == sign.getStartMonth() && day>=sign.getStartDay()) + || (month == sign.getEndMonth() && day<=sign.getEndDay())) { + return sign; + } + } + return null; // This should be impossible... + } +} diff --git a/src/com/lilithsthrone/utils/time/ChineseCalendar.java b/src/com/lilithsthrone/utils/time/ChineseCalendar.java new file mode 100644 index 0000000000..8a4843f4de --- /dev/null +++ b/src/com/lilithsthrone/utils/time/ChineseCalendar.java @@ -0,0 +1,70 @@ +package com.lilithsthrone.utils.time; + +import java.time.LocalDateTime; + +public enum ChineseCalendar { + ONE(0, 2, 5), + TWO(1, 1, 24), + THREE(2, 2, 13), + FOUR(3, 2, 2), + FIVE(4, 1, 23), + SIX(5, 2, 10), + SEVEN(6, 1, 30), + EIGHT(7, 2, 17), + NINE(8, 2, 6), + TEN(9,1, 26), + ELEVEN(10, 2, 14), + TWELVE(11, 2, 4), + THIRTEEN(12, 1, 24), + FOURTEEN(13, 2, 11), + FIFTEEN(14, 1, 31), + SIXTEEN(15, 2, 19), + SEVENTEEN(16, 2, 8), + EIGHTEEN(17, 1, 27), + NINETEEN(18, 2, 15); + + private final int index; + private final int startMonth; + private final int startDay; + ChineseCalendar(int index, int startMonth, int startDay) { + this.index = index; + this.startMonth = startMonth; + this.startDay = startDay; + } + + public int getIndex() { + return index; + } + + public int getStartMonth() { + return startMonth; + } + + public int getStartDay() { + return startDay; + } + + public static ChineseCalendar getCycleFromIndex(int index) { + for(ChineseCalendar cycle : ChineseCalendar.values()) { + if (cycle.index == index) { + return cycle; + } + } + return null; + } + + public static int getCycleFromDate(LocalDateTime dateTime) { + int day = dateTime.getDayOfMonth(); + int month = dateTime.getMonthValue(); + // Remove 5 from the year to bring it inline with the chinese calendar https://en.wikipedia.org/wiki/Chinese_zodiac#Years + int index = (dateTime.getYear() - 5) % 19; + ChineseCalendar cycle = getCycleFromIndex(index); + if (cycle == null) { + return -1; + } + if (month < cycle.getStartMonth() || (month == cycle.getStartMonth() && day < cycle.getStartDay())) { + return index - 1; + } + return index; + } +} diff --git a/src/com/lilithsthrone/utils/time/ChineseZodiac.java b/src/com/lilithsthrone/utils/time/ChineseZodiac.java new file mode 100644 index 0000000000..179ca87fd1 --- /dev/null +++ b/src/com/lilithsthrone/utils/time/ChineseZodiac.java @@ -0,0 +1,56 @@ +package com.lilithsthrone.utils.time; + +import java.time.LocalDateTime; + +public enum ChineseZodiac { + RAT("rat", 0), + COW("cow", 1), + TIGER("tiger", 2), + RABBIT("rabbit", 3), + DRAGON("dragon", 4), + LAMIA("lamia", 5), + HORSE("horse", 6), + GOAT("goat", 7), + HARPY("harpy", 8), + DEMON("demon", 9), + DOG("dog", 10), + PIG("pig", 11); + + private final String name; + private final int index; + + ChineseZodiac(String name, int index) { + this.name = name; + this.index = index; + } + + public String getName() { + return name; + } + + public int getIndex() { + return index; + } + + @Override + public String toString() { + return getName(); + } + + public static ChineseZodiac getSignFromDate(LocalDateTime dateTime) { + // Remove 4 from the year to bring it inline with the chinese calendar https://en.wikipedia.org/wiki/Chinese_zodiac#Years + int signIndex = (dateTime.getYear() - 4) % 12; + if (ChineseCalendar.getCycleFromDate(dateTime) != (dateTime.getYear() - 5) % 19) { + signIndex--; + if (signIndex < 0) { + signIndex = 11; + } + } + for(ChineseZodiac sign : ChineseZodiac.values()) { + if (signIndex == sign.index) { + return sign; + } + } + return null; // This should be impossible... + } +}