diff --git a/documentation/changeLog.txt b/documentation/changeLog.txt index e93b4c66c..23deedc2b 100644 --- a/documentation/changeLog.txt +++ b/documentation/changeLog.txt @@ -4,11 +4,32 @@ http://onehouronelife.com/updateLog.php -Version 393 ??? +Version 394 2023-October-6 --New /MOTHER command to locate your mother (sometimes she's not your leader, so the /LEADER command doesn't always work to find her). Fixes #926 +--Support for using extra animation slots in emotes. + + + + +Editor Fixes: + +--Made animation freeze slider in scene editor cover more time range, to be + able to feeze action later in an animation. + +--Sound widget now has text field for volume instead of just a slider, making + even quieter volumes settable. + +--Animation editor can now clone extras animations from one person to all other + people, with intelligent matching of sprites (with same position and age + range). + +--Animation editor can now clone extras from one person object to another. + +--Scene editor can now display gesture emotes. + diff --git a/gameSource/EditorAnimationPage.cpp b/gameSource/EditorAnimationPage.cpp index f36bf79f7..c0d2dc4e4 100644 --- a/gameSource/EditorAnimationPage.cpp +++ b/gameSource/EditorAnimationPage.cpp @@ -138,7 +138,20 @@ EditorAnimationPage::EditorAnimationPage() mFullSoundPasteButton( smallFont, 130, -328, "Full Sound Paste" ), mSpeedMultField( smallFont, -500, -328, 4, false, "Speed x", "0123456789." ), - mSpeedMultApplyButton( smallFont, -446, -328, "Apply" ) { + mSpeedMultApplyButton( smallFont, -446, -328, "Apply" ), + mCloneExtrasToOtherPeopleButton( + smallFont, 390, 310, + "Clone Extras to All People" ), + mCloneExtrasToOtherPeopleButtonConfirm( + smallFont, 190, 310, + "Really?" ), + mCopyExtrasButton( + smallFont, 560, 310, + "Copy Extras" ), + mClonedExtrasObjectID( -1 ), + mPasteClonedExtrasButton( + smallFont, 190, 310, + "Paste Extras and Save" ) { for( int i=0; i<=extraB; i++ ) { @@ -536,6 +549,23 @@ EditorAnimationPage::EditorAnimationPage() addKeyDescription( &mKeyLegend, 'h', "Hide/show UI" ); addKeyClassDescription( &mKeyLegendB, "R-Click", "Copy animations" ); + + + addComponent( &mCloneExtrasToOtherPeopleButton ); + addComponent( &mCloneExtrasToOtherPeopleButtonConfirm ); + addComponent( &mCopyExtrasButton ); + + mCloneExtrasToOtherPeopleButton.addActionListener( this ); + mCloneExtrasToOtherPeopleButtonConfirm.addActionListener( this ); + mCopyExtrasButton.addActionListener( this ); + + mCloneExtrasToOtherPeopleButton.setVisible( false ); + mCloneExtrasToOtherPeopleButtonConfirm.setVisible( false ); + mCopyExtrasButton.setVisible( false ); + + addComponent( &mPasteClonedExtrasButton ); + mPasteClonedExtrasButton.addActionListener( this ); + mPasteClonedExtrasButton.setVisible( false ); } @@ -681,6 +711,136 @@ static AnimationRecord *createRecordForObject( int inObjectID, +static void cloneExtrasBetweenPeople( int inSourceObjectID, + int inDestObjectID ) { + + ObjectRecord *sourceO = getObject( inSourceObjectID ); + + ObjectRecord *currentO = getObject( inDestObjectID ); + + + // clear the old ones first, because we might have a + // different number of extras now + int oldExtras = getNumExtraAnim( inDestObjectID ); + + for( int i=0; isoundAnim; + + newRecord->numSounds = sourceRecord->numSounds; + + newRecord->soundAnim = + new SoundAnimationRecord[ newRecord->numSounds ]; + for( int s=0; s < newRecord->numSounds; s++ ) { + newRecord->soundAnim[s] = + copyRecord( sourceRecord->soundAnim[s] ); + } + + + for( int s=0; s < sourceRecord->numSlots; s++ ) { + if( s < currentO->numSlots ) { + newRecord->slotAnim[s] = sourceRecord->slotAnim[s]; + } + } + + + + // walk through each sprite animation in sourceRecord + // For each one, look at sprite's: + // --id + // --position + // --age start and end + // Then walk through the inDestObjectID object and look + // for a sprite that matches all three of these things + // + // --If found, copy that sprite animation into the corresponding + // slot in newRecord + + for( int s=0; s < sourceRecord->numSprites; s++ ) { + + int id = sourceO->sprites[s]; + doublePair pos = sourceO->spritePos[s]; + + double ageStart = sourceO->spriteAgeStart[s]; + double ageEnd = sourceO->spriteAgeEnd[s]; + + + for( int s2=0; s2 < currentO->numSprites; s2++ ) { + + if( currentO->sprites[s2] == id + && + equal( currentO->spritePos[s2], pos ) + && + currentO->spriteAgeStart[s2] == ageStart + && + currentO->spriteAgeEnd[s2] == ageEnd ) { + + // a match + + newRecord->spriteAnim[s2] = + sourceRecord->spriteAnim[s]; + } + } + } + addAnimation( newRecord ); + + freeRecord( newRecord ); + } + } + + + + + +// clone extra animations from inSourceObjectID to all other person objects +// in the object bank +static void cloneExtrasToOtherPeople( int inSourceObjectID ) { + + int firstPersonID = getNextPersonObject( -1 ); + + int currentPersonID = firstPersonID; + + + + + while( true ) { + + if( currentPersonID == inSourceObjectID ) { + // skip source person + currentPersonID = getNextPersonObject( currentPersonID ); + continue; + } + + cloneExtrasBetweenPeople( inSourceObjectID, currentPersonID ); + + currentPersonID = getNextPersonObject( currentPersonID ); + + // looped back around + if( currentPersonID == firstPersonID ) { + break; + } + } + } + + + + void EditorAnimationPage::populateCurrentAnim() { freeCurrentAnim(); @@ -832,6 +992,12 @@ void EditorAnimationPage::checkNextPrevVisible() { mCopyChainRandButton.setVisible( false ); mCopyWalkButton.setVisible( false ); mCopyUpButton.setVisible( false ); + + mCloneExtrasToOtherPeopleButton.setVisible( false ); + mCloneExtrasToOtherPeopleButtonConfirm.setVisible( false ); + + mPasteClonedExtrasButton.setVisible( false ); + mCopyExtrasButton.setVisible( false ); return; } @@ -874,9 +1040,19 @@ void EditorAnimationPage::checkNextPrevVisible() { if( r->person ) { mCopyWalkButton.setVisible( true ); + mCloneExtrasToOtherPeopleButton.setVisible( true ); + mCloneExtrasToOtherPeopleButtonConfirm.setVisible( false ); + mCopyExtrasButton.setVisible( true ); + + if( mClonedExtrasObjectID > 0 && + mCurrentObjectID != mClonedExtrasObjectID ) { + mPasteClonedExtrasButton.setVisible( true ); + } } else { mCopyWalkButton.setVisible( false ); + mCloneExtrasToOtherPeopleButton.setVisible( false ); + mCloneExtrasToOtherPeopleButtonConfirm.setVisible( false ); } @@ -2444,6 +2620,33 @@ void EditorAnimationPage::actionPerformed( GUIComponent *inTarget ) { mSpeedMultField.setText( "1.0" ); } } + else if( inTarget == &mCloneExtrasToOtherPeopleButton ) { + mCloneExtrasToOtherPeopleButton.setVisible( false ); + mCloneExtrasToOtherPeopleButtonConfirm.setVisible( true ); + } + else if( inTarget == &mCloneExtrasToOtherPeopleButtonConfirm ) { + mCloneExtrasToOtherPeopleButton.setVisible( false ); + mCloneExtrasToOtherPeopleButtonConfirm.setVisible( false ); + + cloneExtrasToOtherPeople( mCurrentObjectID ); + + mClonedExtrasObjectID = mCurrentObjectID; + } + else if( inTarget == &mCopyExtrasButton ) { + mClonedExtrasObjectID = mCurrentObjectID; + mCopyExtrasButton.setVisible( false ); + } + else if( inTarget == &mPasteClonedExtrasButton ) { + cloneExtrasBetweenPeople( mClonedExtrasObjectID, mCurrentObjectID ); + + // re-pick current object + actionPerformed( &mObjectPicker ); + + // switch to extras + actionPerformed( mCheckboxes[5] ); + + mPasteClonedExtrasButton.setVisible( false ); + } else { AnimType oldType = mCurrentType; diff --git a/gameSource/EditorAnimationPage.h b/gameSource/EditorAnimationPage.h index db3c590c3..2fe9a4b00 100644 --- a/gameSource/EditorAnimationPage.h +++ b/gameSource/EditorAnimationPage.h @@ -279,6 +279,16 @@ class EditorAnimationPage : public GamePage, public ActionListener { TextField mSpeedMultField; TextButton mSpeedMultApplyButton; + + TextButton mCloneExtrasToOtherPeopleButton; + TextButton mCloneExtrasToOtherPeopleButtonConfirm; + + TextButton mCopyExtrasButton; + + int mClonedExtrasObjectID; + + TextButton mPasteClonedExtrasButton; + void checkNextPrevVisible(); diff --git a/gameSource/EditorScenePage.cpp b/gameSource/EditorScenePage.cpp index 4c3d79f11..7cf1a6ae3 100644 --- a/gameSource/EditorScenePage.cpp +++ b/gameSource/EditorScenePage.cpp @@ -83,7 +83,7 @@ EditorScenePage::EditorScenePage() true, 2 ), mCellAnimFreezeSlider( smallFont, -450, -340, 2, 300, 20, - -2, 2, "Cell Time" ), + -2, 4, "Cell Time" ), mPersonAnimFreezeSlider( smallFont, 50, -340, 2, 300, 20, -2, 2, "Person Time" ), @@ -1493,6 +1493,18 @@ void EditorScenePage::drawUnderComponents( doublePair inViewCenter, ClothingSet clothingToDraw = p->clothing; + AnimType aType = p->anim; + + + // for now, only first emote in comma-separated + // list of emots can have extra anim associated + // with it + if( p->currentEmot != NULL && + p->currentEmot->extraAnimIndex > -1 ) { + aType = extra; + setExtraIndex( p->currentEmot->extraAnimIndex ); + } + if( splitHeld ) { // don't actually draw person now // sandwitch them in between layers of @@ -1506,7 +1518,7 @@ void EditorScenePage::drawUnderComponents( doublePair inViewCenter, drawObjectAnim( p->oID, 2, p->anim, thisFrameTime, 0, - p->anim, + aType, thisFrameTime, frozenRotFrameTime, &used, diff --git a/gameSource/LivingLifePage.cpp b/gameSource/LivingLifePage.cpp index 23edd76f5..1ed640b73 100644 --- a/gameSource/LivingLifePage.cpp +++ b/gameSource/LivingLifePage.cpp @@ -4905,10 +4905,12 @@ ObjectAnimPack LivingLifePage::drawLiveObject( ( inObj->lastHoldingID > 0 && getObject( inObj->lastHoldingID )->rideable ) ) { - if( curType == ground2 || curType == moving ) { + if( curType == ground2 || curType == moving || + curType == extra || curType == extraB ) { frozenArmType = moving; } - if( fadeTargetType == ground2 || fadeTargetType == moving ) { + if( fadeTargetType == ground2 || fadeTargetType == moving || + fadeTargetType == extra || fadeTargetType == extraB ) { frozenArmFadeTargetType = moving; } } @@ -13424,7 +13426,7 @@ void LivingLifePage::step() { - if( ourObject != NULL ) { + if( ourObject != NULL && areLiveTriggersEnabled() ) { char newTrigger = false; AnimType anim = stepLiveTriggers( &newTrigger ); @@ -16764,6 +16766,8 @@ void LivingLifePage::step() { o.currentEmot = NULL; o.emotClearETATime = 0; + o.extraAnimType = extraB; + o.killMode = false; o.killWithID = -1; o.chasingUs = false; @@ -20192,6 +20196,49 @@ void LivingLifePage::step() { if( oldEmot != existing->currentEmot && existing->currentEmot != NULL ) { newEmotPlaySound = existing->currentEmot; + + } + + if( existing->currentEmot != NULL ) { + if( existing->currentEmot->extraAnimIndex + > -1 + && + computeCurrentAge( existing ) >= 1 ) { + + // don't allow extra animations + // for emotes for people who + // are less that 1 year old + // since they can revert back + // to crying at any time + // and we don't want to interfere + // with their crying animaton + + + // toggle back and forth + // between extra slots so that + // extra animations can transition + // smoothly + if( existing->extraAnimType == + extraB ) { + + setExtraIndex( + existing-> + currentEmot->extraAnimIndex ); + + addNewAnimPlayerOnly( existing, + extra ); + existing->extraAnimType = extra; + } + else { + setExtraIndexB( + existing-> + currentEmot->extraAnimIndex ); + + addNewAnimPlayerOnly( existing, + extraB ); + existing->extraAnimType = extraB; + } + } } } diff --git a/gameSource/LivingLifePage.h b/gameSource/LivingLifePage.h index 28e0fa62d..c7b402c82 100644 --- a/gameSource/LivingLifePage.h +++ b/gameSource/LivingLifePage.h @@ -325,6 +325,13 @@ typedef struct LiveObject { SimpleVector permanentEmots; + // either extra or extraB + // toggle back and forth as we switch emotes that have + // extraAnimIndex defined + AnimType extraAnimType; + + + char killMode; int killWithID; diff --git a/gameSource/SoundWidget.cpp b/gameSource/SoundWidget.cpp index 296d0b4bf..b94b9c970 100644 --- a/gameSource/SoundWidget.cpp +++ b/gameSource/SoundWidget.cpp @@ -41,8 +41,8 @@ SoundWidget::SoundWidget( Font *inDisplayFont, mClearButton( "clearButton.tga", 17, 0 ), mCopyButton( "copyButton.tga", 51, 0 ), mPasteButton( "pasteButton.tga", 85, 0 ), - mVolumeSlider( inDisplayFont, -70, -30, 2, - 124, 20, + mVolumeSlider( inDisplayFont, 10, -30, 2, + 44, 20, 0, 1.0, "V" ), mDefaultVolumeButton( inDisplayFont, 118, -30, "D" ) { @@ -85,7 +85,7 @@ SoundWidget::SoundWidget( Font *inDisplayFont, styleButton( &mDefaultVolumeButton ); - mVolumeSlider.toggleField( false ); + mVolumeSlider.toggleField( true ); mVolumeSlider.addActionListener( this ); diff --git a/gameSource/emotion.cpp b/gameSource/emotion.cpp index eac38c9a4..163051591 100644 --- a/gameSource/emotion.cpp +++ b/gameSource/emotion.cpp @@ -68,15 +68,16 @@ void initEmotion() { e->faceEmot = 0; e->bodyEmot = 0; e->headEmot = 0; - + e->extraAnimIndex = -1; - sscanf( parts[i], "%d %d %d %d %d %d", + sscanf( parts[i], "%d %d %d %d %d %d %d", &( e->eyeEmot ), &( e->mouthEmot ), &( e->otherEmot ), &( e->faceEmot ), &( e->bodyEmot ), - &( e->headEmot ) ); + &( e->headEmot ), + &( e->extraAnimIndex ) ); } delete [] parts[i]; } diff --git a/gameSource/emotion.h b/gameSource/emotion.h index 7b114e2c5..c63af46db 100644 --- a/gameSource/emotion.h +++ b/gameSource/emotion.h @@ -33,6 +33,11 @@ typedef struct Emotion { // drawn on top of everything (like a hat) int headEmot; + // -1 for no extra animation + // note that this field is optional in lines of emotionObjects.ini + // if not present, defaults to -1 + int extraAnimIndex; + } Emotion; diff --git a/gameSource/game.cpp b/gameSource/game.cpp index f151fc815..8432e9a7c 100644 --- a/gameSource/game.cpp +++ b/gameSource/game.cpp @@ -1,4 +1,4 @@ -int versionNumber = 391; +int versionNumber = 394; int dataVersionNumber = 0; int binVersionNumber = versionNumber; diff --git a/gameSource/languages/English.txt b/gameSource/languages/English.txt index 736feb52f..954ced84c 100644 --- a/gameSource/languages/English.txt +++ b/gameSource/languages/English.txt @@ -810,7 +810,7 @@ pauseMessage4 "-" -commandHintsA "CHAT COMMANDS:##~~##/FAM##/DIE##/DISCONNECT##/FPS##/NETWORK##/PING####/HAPPY##/MAD##/ANGRY##/SAD##/DEVIOUS##/JOY##/BLUSH##/HUBBA##/ILL##/YOOHOO##/HMPH##/LOVE##/OREALLY##/SHOCK" +commandHintsA "CHAT COMMANDS:##~~##/FAM##/DIE##/DISCONNECT##/FPS##/NETWORK##/PING####/HAPPY /POINT##/MAD /WAIT##/ANGRY /WAVE##/SAD /HERE##/DEVIOUS##/JOY /UPYOURS##/BLUSH##/HUBBA##/ILL##/YOOHOO##/HMPH##/LOVE##/OREALLY##/SHOCK" commandHintsB "/LEADER /MOTHER##/FOLLOWER##/ALLY /ORDER##/UNFOLLOW##/PROPERTY####I AM [NAME]##YOU ARE [NAME]##CURSE [NAME]##I FORGIVE [NAME]##[NAME] OWNS THIS##I'LL KILL [NAME]##I JOIN YOU##I FOLLOW [NAME]##I EXILE [NAME]##I REDEEM [NAME]##ORDER, [TEXT]##~~##NOTE:##~~##'YOU' FOR [NAME]##IS CLOSEST PERSON##LIKE: 'CURSE YOU'" diff --git a/gameSource/liveAnimationTriggers.cpp b/gameSource/liveAnimationTriggers.cpp index 87ad14bb3..5ad37d6b2 100644 --- a/gameSource/liveAnimationTriggers.cpp +++ b/gameSource/liveAnimationTriggers.cpp @@ -163,6 +163,11 @@ void freeLiveTriggers() { +char areLiveTriggersEnabled() { + return enabled; + } + + char anyLiveTriggersLeft() { if( !enabled ) { diff --git a/gameSource/liveAnimationTriggers.h b/gameSource/liveAnimationTriggers.h index 147f6f6f7..981c390d0 100644 --- a/gameSource/liveAnimationTriggers.h +++ b/gameSource/liveAnimationTriggers.h @@ -9,6 +9,8 @@ void initLiveTriggers(); void freeLiveTriggers(); +char areLiveTriggersEnabled(); + char anyLiveTriggersLeft(); diff --git a/gameSource/settings/emotionObjects.ini b/gameSource/settings/emotionObjects.ini index 38fe3e00e..0b957fcb3 100644 --- a/gameSource/settings/emotionObjects.ini +++ b/gameSource/settings/emotionObjects.ini @@ -31,4 +31,9 @@ 0 3945 0 0 0 0 1841 4184 0 0 0 0 0 4313 0 0 0 0 -0 0 4744 0 0 0 \ No newline at end of file +0 0 4744 0 0 0 +0 0 0 0 0 0 0 +0 0 0 0 0 0 1 +0 0 0 0 0 0 2 +0 0 0 0 0 0 3 +1839 1842 0 0 0 0 4 \ No newline at end of file diff --git a/gameSource/settings/emotionWords.ini b/gameSource/settings/emotionWords.ini index d81e52e3e..b0526394c 100644 --- a/gameSource/settings/emotionWords.ini +++ b/gameSource/settings/emotionWords.ini @@ -31,4 +31,9 @@ *refuseFood *starving *satisfied -*headless \ No newline at end of file +*headless +/point +/wait +/wave +/here +/upyours \ No newline at end of file diff --git a/server/settings/allowedEmotRange.ini b/server/settings/allowedEmotRange.ini index 3f10ffe7a..c24b6ae77 100644 --- a/server/settings/allowedEmotRange.ini +++ b/server/settings/allowedEmotRange.ini @@ -1 +1 @@ -15 \ No newline at end of file +38 \ No newline at end of file diff --git a/server/settings/forbiddenEmots.ini b/server/settings/forbiddenEmots.ini index a55e2a546..3b2eb79ba 100644 --- a/server/settings/forbiddenEmots.ini +++ b/server/settings/forbiddenEmots.ini @@ -1,3 +1,20 @@ 7 8 -16 \ No newline at end of file +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 \ No newline at end of file