Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Soujuurou/Charlotte #1811

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ fun SkillCommandGroup(
errorMessage = ""
} catch (e: Exception) {
// TODO: Localize
errorMessage = "Invalid skill command"
errorMessage = "Invalid skill command ${e.cause?.message}"
}
},
onCancel = { editing = false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,14 @@ fun SkillMakerUI(
),
onMelusine = {
vm.targetSkill(ServantTarget.Melusine)
},
showSoujuurou = nav.skill in listOf(
Skill.Servant.A3,
Skill.Servant.B3,
Skill.Servant.C3
),
onSoujuurou = {
navigate(SkillMakerNav.Soujuurou(nav.skill))
}
)
}
Expand All @@ -189,6 +197,13 @@ fun SkillMakerUI(
is SkillMakerNav.KukulkanTarget -> {
SkillMakerKukulkanTarget(onSkillTarget = { vm.targetSkill(listOf(nav.firstTarget, it)) })
}
is SkillMakerNav.Soujuurou -> {
SkillMakerSoujuurou(
onSkillTarget = { servantTarget ->
vm.targetSkill(servantTarget)
},
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,42 @@ import io.github.fate_grand_automata.scripts.models.Skill

sealed class SkillMakerEntry {
class Action(val action: AutoSkillAction) : SkillMakerEntry() {
private fun toString(skill: Skill, target: ServantTarget?) =
if (target == null)
"${skill.autoSkillCode}"
else "${skill.autoSkillCode}${target.autoSkillCode}"

private fun toString(skill: Skill, targets: List<ServantTarget>) =
if (targets.isEmpty()) "${skill.autoSkillCode}"
else if (targets.size == 1) "${skill.autoSkillCode}${targets[0].autoSkillCode}"
else "${skill.autoSkillCode}(${targets.map(ServantTarget::autoSkillCode).joinToString("")})"
private fun toString(skill: Skill, target: ServantTarget?) = when (target) {
null -> "${skill.autoSkillCode}"
else -> {
if (target.specialTarget.isNotEmpty()) {
"${skill.autoSkillCode}${target.autoSkillCode}${target.specialTarget}]"
} else {
"${skill.autoSkillCode}${target.autoSkillCode}"
}
}
}

private fun toString(skill: Skill, targets: List<ServantTarget>) = when {
targets.isEmpty() -> "${skill.autoSkillCode}"
targets.size == 1 -> {
if (targets[0].specialTarget.isNotEmpty()) {
"${skill.autoSkillCode}${targets[0].autoSkillCode}${targets[0].specialTarget}]"
} else {
"${skill.autoSkillCode}${targets[0].autoSkillCode}"
}
}

else -> {
val start = "${skill.autoSkillCode}("
val end = ")"

val middle = targets.joinToString("") { target ->
if (target.specialTarget.isNotEmpty()) {
"${target.autoSkillCode}${target.specialTarget}]"
} else {
"${target.autoSkillCode}"
}
}

start + middle + end
}
}

override fun toString() = when (action) {
is AutoSkillAction.Atk -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import io.github.fate_grand_automata.scripts.models.ServantTarget
import io.github.fate_grand_automata.scripts.models.Skill

sealed class SkillMakerNav {
object Main : SkillMakerNav()
object MasterSkills : SkillMakerNav()
object Atk : SkillMakerNav()
object OrderChange : SkillMakerNav()
data object Main : SkillMakerNav()
data object MasterSkills : SkillMakerNav()
data object Atk : SkillMakerNav()
data object OrderChange : SkillMakerNav()
data class SkillTarget(val skill: Skill) : SkillMakerNav()
data class Emiya(val skill: Skill) : SkillMakerNav()
data class SpaceIshtar(val skill: Skill) : SkillMakerNav()
data class Kukulkan(val skill: Skill) : SkillMakerNav()
data class KukulkanTarget(val skill: Skill, val firstTarget: ServantTarget) : SkillMakerNav()
data class Soujuurou(val skill: Skill) : SkillMakerNav()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package io.github.fate_grand_automata.ui.skill_maker

import android.content.res.Configuration
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import io.github.fate_grand_automata.R
import io.github.fate_grand_automata.scripts.models.ServantTarget
import io.github.fate_grand_automata.ui.FGATheme
import io.github.fate_grand_automata.ui.FGATitle


@Composable
fun SkillMakerSoujuurou(
onSkillTarget: (ServantTarget) -> Unit
) {
Column(
modifier = Modifier
.fillMaxHeight()
.padding(16.dp)
) {
FGATitle(
stringResource(R.string.skill_maker_soujuurou)
)

Row(
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.weight(1f)
.fillMaxWidth()
) {
TargetButton(
onClick = { onSkillTarget(ServantTarget.SpecialTarget.TriChoice1) },
color = colorResource(R.color.colorQuickResist),
text = stringResource(R.string.skill_maker_tri_choice_1)
)

TargetButton(
onClick = { onSkillTarget(ServantTarget.SpecialTarget.TriChoice2) },
color = colorResource(R.color.colorArtsResist),
text = stringResource(R.string.skill_maker_tri_choice_2)
)

TargetButton(
onClick = { onSkillTarget(ServantTarget.SpecialTarget.TriChoice3) },
color = colorResource(R.color.colorBuster),
text = stringResource(R.string.skill_maker_tri_choice_3)
)
}

}
}

@Preview(name = "Light Mode", widthDp = 600, heightDp = 300)
@Preview(name = "Dark Mode", widthDp = 600, heightDp = 300, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun TestSoujuurou() {
FGATheme {
SkillMakerSoujuurou(onSkillTarget = { })
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ fun SkillMakerTarget(
showKukulkan: Boolean,
onKukulkan: () -> Unit,
showMelusine: Boolean,
onMelusine: () -> Unit
onMelusine: () -> Unit,
showSoujuurou: Boolean,
onSoujuurou: () -> Unit
) {
Column(
modifier = Modifier
Expand Down Expand Up @@ -97,6 +99,11 @@ fun SkillMakerTarget(
Text(stringResource(R.string.skill_maker_melusine))
}
}
if (showSoujuurou) {
Button(onClick = onSoujuurou) {
Text(stringResource(R.string.skill_maker_soujuurou))
}
}

Button(onClick = { onSkillTarget(null) }) {
Text(stringResource(R.string.skill_maker_target_none))
Expand All @@ -120,12 +127,18 @@ fun TestSkillMakerTargetIshtar() = TestSkillMaker(showSpaceIshtar = true)
@Preview(name = "Dark Mode", widthDp = 600, heightDp = 300, uiMode = Configuration.UI_MODE_NIGHT_YES)
fun TestSkillMakerOnlyKukulkan() = TestSkillMaker()

@Composable
@Preview(name = "Light Mode", widthDp = 600, heightDp = 300)
@Preview(name = "Dark Mode", widthDp = 600, heightDp = 300, uiMode = Configuration.UI_MODE_NIGHT_YES)
fun TestSkillMakerTargetSoujuurou() = TestSkillMaker(showSoujuurou = true)

@Composable
private fun TestSkillMaker(
showEmiya: Boolean = false,
showKukulkan: Boolean = false,
showSpaceIshtar: Boolean = false,
showMelusine: Boolean = showEmiya
showSpaceIshtar: Boolean = false,
showMelusine: Boolean = showEmiya,
showSoujuurou: Boolean = false
) {
FGATheme {
SkillMakerTarget(
Expand All @@ -137,7 +150,9 @@ private fun TestSkillMaker(
showKukulkan = showKukulkan,
onKukulkan = {},
showMelusine = showMelusine,
onMelusine = {}
onMelusine = {},
showSoujuurou = showSoujuurou,
onSoujuurou = {}
)
}
}
1 change: 1 addition & 0 deletions app/src/main/res/values-ja/localized.xml
Original file line number Diff line number Diff line change
Expand Up @@ -390,4 +390,5 @@
<string name="p_max_gold_ember_total_count">"受け取った種火の総数"</string>
<string name="update_download_success">"ダウンロード成功。5秒後に再起動します。"</string>
<string name="skill_maker_melusine">"メリュジーヌ"</string>
<string name="skill_maker_soujuurou">"静希草十郎"</string>
</resources>
4 changes: 4 additions & 0 deletions app/src/main/res/values/localized.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ Skills"</string>
<string name="skill_maker_quick">"Quick"</string>
<string name="skill_maker_arts">"Arts"</string>
<string name="skill_maker_buster">"Buster"</string>
<string name="skill_maker_tri_choice_1">"Choice 1"</string>
<string name="skill_maker_tri_choice_2">"Choice 2"</string>
<string name="skill_maker_tri_choice_3">"Choice 3"</string>
<string name="skill_maker_kukulkan">"Kukulkan"</string>
<string name="skill_maker_option_1">"Option 1"</string>
<string name="skill_maker_option_2">"Option 2"</string>
Expand Down Expand Up @@ -386,6 +389,7 @@ After pressing on the button, switch the app filter from \"Not optimized\" to \"
<string name="p_max_gold_ember_total_count">"Max Gold ember total count"</string>
<string name="update_download_success">"Download successful. Restarting app in 5 seconds."</string>
<string name="skill_maker_melusine">"Mélusine"</string>
<string name="skill_maker_soujuurou">"Soujuurou"</string>

<string name="reset_all">"Reset all"</string>
<string name="reset_to_default">"Reset to default"</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ class BattleScreenLocations @Inject constructor(
ServantTarget.Option1 -> 0
ServantTarget.Option2 -> 470
ServantTarget.Melusine -> null
ServantTarget.SpecialTarget.TriChoice1 -> -200
ServantTarget.SpecialTarget.TriChoice2 -> 300
ServantTarget.SpecialTarget.TriChoice3 -> 670
}?.let { x -> Location(x, 880) }?.xFromCenter()

fun locate(skill: Skill.Servant) = when (skill) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,51 @@ class AutoSkillCommand private constructor(
}

companion object {

// Prepare the list of special targets
private val specialTargetList = ServantTarget
.list
.filter {
it.specialTarget.isNotEmpty()
}

private fun getTarget(queue: Queue<Char>): ServantTarget? {
val peekTarget = queue.peek()
val target = ServantTarget.list.firstOrNull { it.autoSkillCode == peekTarget }
if (target != null) {
var target: ServantTarget? = null
if (peekTarget == '[') {
// remove initial [
queue.remove()
}

var special = ""
var char: Char? = null

while (queue.isNotEmpty()) {
char = queue.remove()
if (char == ']') break

if (char != '[') {
special += char
}
target = specialTargetList
.firstOrNull {
it.specialTarget == special
}
}
if (char != ']') {
throw Exception("Found [ but no matching ] in Skill Command")
}
if (special.isEmpty()) {
throw Exception("Command Can't be empty")
}
if (target == null) {
throw Exception("Special target \"$special\" not found")
}
} else {
target = ServantTarget.list.firstOrNull { it.autoSkillCode == peekTarget }
if (target != null) {
queue.remove()
}
}
return target
}

Expand All @@ -37,15 +75,48 @@ class AutoSkillCommand private constructor(
if (nextChar == '(') {
queue.remove()
var char: Char? = null
var specialFound = false
var special = ""
while (queue.isNotEmpty()) {
char = queue.remove()
if (char == ')') break
val target = ServantTarget.list.firstOrNull { it.autoSkillCode == char }
target?.let(targets::add)

if (char == '[') {
specialFound = true
} else if (char == ']') {
specialFound = false
val target = specialTargetList.firstOrNull {
it.specialTarget == special
}
target?.let {
targets.add(it)

// reset
special = ""
} ?: run {
if (special.isEmpty()) {
throw Exception("Command Can't be empty")
} else {
throw Exception("Special target \"$special\" not found")
}
}
}

if (specialFound) {
if (char != '[') {
special += char
}
} else {
val target = ServantTarget.list.firstOrNull { it.autoSkillCode == char }
target?.let(targets::add)
}
}
if (char != ')') {
throw Exception("Found ( but no matching ) in Skill Command")
}
if (specialFound) {
throw Exception("Found [ but no matching ] in Skill Command")
}
} else {
getTarget(queue)?.let(targets::add)
}
Expand Down
Loading