diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..f97e855f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "KodeUI"] + path = KodeUI + url = https://github.com/sarbian/KodeUI.git diff --git a/Assets/DefaultSkin.cfg b/Assets/DefaultSkin.cfg new file mode 100644 index 00000000..3fe2b006 --- /dev/null +++ b/Assets/DefaultSkin.cfg @@ -0,0 +1,471 @@ +KodeUI_Skin { + name = EL.Default + Style { + name = default + } + Style { + name = ScrollView + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = Viewport + sprite = EL.Default.mask + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = Scrollbar + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = Scrollbar.Handle + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = TabController + sprite = EL.Default.tabempty + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = TabItemView + sprite = EL.Default.tabdesel + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = TabItemView.Selected + sprite = EL.Default.tabsel + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = TabItemView.Label + color = 1, 1, 1, 1 + margin = 5, 5, 4, 4 + } + Style { + name = LayoutPanel + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = UIButton + sprite = EL.Default.button + color = 0.5, 0.5, 0.5, 1 + } + Style { + name = ButtonText + sprite = EL.Default.button + color = 1, 1, 1, 1 + margin = 5, 5, 4, 4 + } + Style { + name = UIDropdown + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = UIDropdown.Label + color = 1, 1, 1, 1 + margin = 5, 5, 4, 4 + } + Style { + name = UIDropdown.Arrow + sprite = EL.Default.dropdown + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = UIDropdown.Template + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = UIDropdown.Scrollbar + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = UIDropdown.Scrollbar.Handle + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = UIDropdown.Viewport + sprite = EL.Default.mask + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = UIDropdown.Item + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = UIDropdown.Item.CheckMark + sprite = EL.Default.checkmark + color = 1, 1, 1, 1 + } + Style { + name = UIDropdown.Item.ItemText + sprite = EL.Default.background + color = 1, 1, 1, 1 + margin = 5, 5, 4, 4 + } + Style { + name = UIInputField + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = UISlider + stateColors { + normalColor = 1, 1, 1, 0.8 + colorMultiplier = 1.25 + } + } + Style { + name = UISlider.Background + sprite = EL.Default.background + color = 0.5, 0.5, 0.5, 0.5 + } + Style { + name = UISlider.Fill + sprite = EL.Default.background + color = 1, 1, 1, 1 + } + Style { + name = UISlider.Handle + sprite = EL.Default.checkmark + color = 1, 1, 1, 1 + } + Style { + name = UIText + color = 1, 1, 1, 1 + } + Style { + name = UIToggle + sprite = EL.Default.toggle_off + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = UIToggle.CheckMark + sprite = EL.Default.toggle_on + color = 0.25, 1, 0.25, 1 + } + + Style { + name = ELPartEditorWindow + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = ELPartItemView + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = ELPartCategoryView + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = ELCraftItemView + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = ELCraftBrowser + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = ELRenameDialog + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = ELShipInfo + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = ELMainWindow + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = Productivity + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = PadSelector + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = PadSelector.Label + sprite = EL.Default.background + color = 1, 1, 1, 1 + } + Style { + name = PadSelector.Arrow + sprite = EL.Default.dropdown + color = 1, 1, 1, 1 + } + Style { + name = PadSelector.Template + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = PadSelector.Scrollbar + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = PadSelector.Scrollbar.Handle + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = PadSelector.Viewport + sprite = EL.Default.mask + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = PadSelector.Item + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = PadSelector.Item.CheckMark + sprite = EL.Default.checkmark + color = 1, 1, 1, 1 + } + Style { + name = PadSelector.Item.ItemText + sprite = EL.Default.background + color = 1, 1, 1, 1 + margin = 5, 5, 4, 4 + } + Style { + name = SiteSelector + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = SiteSelector.Label + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = SiteSelector.Arrow + sprite = EL.Default.dropdown + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = SiteSelector.Template + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = SiteSelector.Scrollbar + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = SiteSelector.Scrollbar.Handle + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = SiteSelector.Viewport + sprite = EL.Default.mask + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = SiteSelector.Item + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = SiteSelector.Item.CheckMark + sprite = EL.Default.checkmark + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = SiteSelector.Item.ItemText + sprite = EL.Default.background + color = 1, 1, 1, 1 + margin = 5, 5, 4, 4 + } + Style { + name = HighlightPad + sprite = EL.Default.toggle_off + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = HighlightPad.CheckMark + sprite = EL.Default.toggle_on + color = 0.25, 1, 0.25, 1 + } + Style { + name = ResourceFraction + stateColors { + normalColor = 1, 1, 1, 0.8 + colorMultiplier = 1.25 + } + } + Style { + name = ResourceFraction.Background + sprite = EL.Default.background + color = 1, 0.890196078, 0.329411765, 1 + } + Style { + name = ResourceFraction.Fill + sprite = EL.Default.background + color = 0, 1, 0.0470588235, 1 + } + Style { + name = ResourceFraction.Handle + sprite = EL.Default.checkmark + color = 1, 1, 1, 1 + } + Style { + name = AmountsPanel + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 + } +} + +KodeUI_Sprite { + name = EL.Default.background + textureUrl = ExtraplanetaryLaunchpads/UI/ui_background + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 8, 8, 8, 8 +} + +KodeUI_Sprite { + name = EL.Default.button + textureUrl = ExtraplanetaryLaunchpads/UI/ui_button + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = FullRect + border = 5, 5, 5, 5 +} + +KodeUI_Sprite { + name = EL.Default.checkmark + textureUrl = ExtraplanetaryLaunchpads/UI/ui_checkmark + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 5, 5, 5, 5 +} + +KodeUI_Sprite { + name = EL.Default.dropdown + textureUrl = ExtraplanetaryLaunchpads/UI/ui_dropdown + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 5, 5, 5, 5 +} + +KodeUI_Sprite { + name = EL.Default.leftturn + textureUrl = ExtraplanetaryLaunchpads/UI/ui_leftturn + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 12, 12, 12, 12 +} + +KodeUI_Sprite { + name = EL.Default.mask + textureUrl = ExtraplanetaryLaunchpads/UI/ui_background + rect = 15, 15, 2, 2 + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 0, 0, 0, 0 +} + +KodeUI_Sprite { + name = EL.Default.rightturn + textureUrl = ExtraplanetaryLaunchpads/UI/ui_rightturn + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 12, 12, 12, 12 +} + +KodeUI_Sprite { + name = EL.Default.tabdesel + textureUrl = ExtraplanetaryLaunchpads/UI/ui_tabdesel + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 8, 8, 8, 8 +} + +KodeUI_Sprite { + name = EL.Default.tabempty + textureUrl = ExtraplanetaryLaunchpads/UI/ui_tabempty + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 8, 8, 8, 8 +} + +KodeUI_Sprite { + name = EL.Default.tabsel + textureUrl = ExtraplanetaryLaunchpads/UI/ui_tabsel + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 8, 8, 8, 8 +} + +KodeUI_Sprite { + name = EL.Default.toggle_off + textureUrl = ExtraplanetaryLaunchpads/UI/ui_toggle_off + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 5, 5, 5, 5 +} + +KodeUI_Sprite { + name = EL.Default.toggle_on + textureUrl = ExtraplanetaryLaunchpads/UI/ui_toggle_on + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 5, 5, 5, 5 +} diff --git a/Assets/EL_UntitledSpacecraft.svg b/Assets/EL_UntitledSpacecraft.svg new file mode 100644 index 00000000..3214c22f --- /dev/null +++ b/Assets/EL_UntitledSpacecraft.svg @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Assets/EL_app.svg b/Assets/EL_app.svg new file mode 100644 index 00000000..dd1537e9 --- /dev/null +++ b/Assets/EL_app.svg @@ -0,0 +1 @@ +EL_appEL \ No newline at end of file diff --git a/Assets/EL_filter.svg b/Assets/EL_filter.svg new file mode 100644 index 00000000..9bfb9793 --- /dev/null +++ b/Assets/EL_filter.svg @@ -0,0 +1 @@ +EL_filterEL \ No newline at end of file diff --git a/Assets/Makefile b/Assets/Makefile index b49581ea..cd739120 100644 --- a/Assets/Makefile +++ b/Assets/Makefile @@ -25,10 +25,29 @@ FLAGS := \ nightheron.png MISC := \ + ELGenericCraftThumb.png \ kairyuu_scaled.png \ plaque.png -all: ${ICONS} ${FLAGS} ${MISC} +UI_IMAGES := \ + ui_background.png \ + ui_button.png \ + ui_checkmark.png \ + ui_dropdown.png \ + ui_leftturn.png \ + ui_rightturn.png \ + ui_tabdesel.png \ + ui_tabempty.png \ + ui_tabsel.png \ + ui_toggle_off.png \ + ui_toggle_on.png \ + $e + +UI_CFG := \ + DefaultSkin.cfg \ + $e + +all: ${ICONS} ${FLAGS} ${MISC} ${UI_IMAGES} info: @echo "Extraplanetary Launchpads Build Information" @@ -40,7 +59,7 @@ info: @echo " zip: ${ZIP}" @echo " KSP Data: ${KSPDIR}" -GUI_ICONS = \ +GUI_ICONS := \ gui_background.png \ gui_flat.png \ gui_raised.png \ @@ -62,24 +81,61 @@ nightheron.png: nightheron.svg kairyuu_scaled.png: kairyuu.svg inkscape --export-width=64 --export-height=40 --export-type=png -o $@ $^ -icon_button.png: icon_button.svg - inkscape --export-width=24 --export-height=24 --export-background-opacity=0 --export-type=png -o $@ $^ +icon_button.png: EL_app.svg + inkscape --export-width=38 --export-height=38 --export-type=png -o $@ $^ + +icon_filter_n.png: EL_filter.svg + sed -e 's/\#[[:xdigit:]]\{6\}/#000000/g' -e 's/\#[[:xdigit:]]\{3\}/#000/g' $^ | inkscape --export-width=32 --export-height=32 --export-type=png -o $@ /dev/stdin + +icon_filter_s.png: EL_filter.svg + sed -e 's/\#[[:xdigit:]]\{6\}/#ffffff/g' -e 's/\#[[:xdigit:]]\{3\}/#fff/g' $^ | inkscape --export-width=32 --export-height=32 --export-type=png -o $@ /dev/stdin + +ELGenericCraftThumb.png: EL_UntitledSpacecraft.svg + inkscape --export-width=256 --export-height=256 --export-type=png -o $@ $^ + +ui_background.png: ui_background.svg + inkscape --export-width=32 --export-height=32 --export-type=png -o $@ $^ + +ui_button.png: ui_button.svg + inkscape --export-width=16 --export-height=16 --export-type=png -o $@ $^ + +ui_checkmark.png: ui_checkmark.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ + +ui_dropdown.png: ui_dropdown.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ + +ui_leftturn.png: ui_leftturn.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ + +ui_rightturn.png: ui_rightturn.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ + +ui_tabdesel.png: ui_tabdesel.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ + +ui_tabempty.png: ui_tabempty.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ + +ui_tabsel.png: ui_tabsel.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ -icon_filter_n.png: icon_button.svg - sed -e 's/\#....../#000000/g' $^ | inkscape --export-width=32 --export-height=32 --export-background-opacity=0 --export-type=png -o $@ /dev/stdin +ui_toggle_off.png: ui_toggle_off.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ -icon_filter_s.png: icon_button.svg - sed -e 's/\#....../#ffffff/g' $^ | inkscape --export-width=32 --export-height=32 --export-background-opacity=0 --export-type=png -o $@ /dev/stdin +ui_toggle_on.png: ui_toggle_on.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ clean: - rm -f kairyuu.png kairyuu_scaled.png icon_button.png icon_filter*.png ${GUI_ICONS} + rm -f ${ICONS} ${FLAGS} ${MISC} ${GUI_ICONS} ${UI_IMAGES} install: all mkdir -p ${MODGAMEDATA}/Agencies ${MODGAMEDATA}/Flags cp kairyuu.png kairyuu_scaled.png ${MODGAMEDATA}/Agencies cp nightheron.png ${MODGAMEDATA}/Flags mkdir -p ${MODGAMEDATA}/Textures - cp icon_button.png icon_filter*.png plaque.png ${MODGAMEDATA}/Textures - #cp ${GUI_ICONS} ${MODGAMEDATA}/Textures + cp ELGenericCraftThumb.png icon_button.png icon_filter*.png plaque.png ${MODGAMEDATA}/Textures + mkdir -p ${MODGAMEDATA}/UI + cp ${UI_CFG} ${UI_IMAGES} ${MODGAMEDATA}/UI .PHONY: all clean install diff --git a/Assets/ui_background.svg b/Assets/ui_background.svg new file mode 100644 index 00000000..9eb4eebd --- /dev/null +++ b/Assets/ui_background.svg @@ -0,0 +1,87 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/Assets/ui_button.svg b/Assets/ui_button.svg new file mode 100644 index 00000000..91d3ec44 --- /dev/null +++ b/Assets/ui_button.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/Assets/ui_checkmark.svg b/Assets/ui_checkmark.svg new file mode 100644 index 00000000..6ab85908 --- /dev/null +++ b/Assets/ui_checkmark.svg @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/Assets/ui_dropdown.svg b/Assets/ui_dropdown.svg new file mode 100644 index 00000000..9ab7927f --- /dev/null +++ b/Assets/ui_dropdown.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/Assets/ui_leftturn.svg b/Assets/ui_leftturn.svg new file mode 100644 index 00000000..3ab52b71 --- /dev/null +++ b/Assets/ui_leftturn.svg @@ -0,0 +1,72 @@ + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/Assets/ui_rightturn.svg b/Assets/ui_rightturn.svg new file mode 100644 index 00000000..169c7d6d --- /dev/null +++ b/Assets/ui_rightturn.svg @@ -0,0 +1,72 @@ + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/Assets/ui_tabdesel.svg b/Assets/ui_tabdesel.svg new file mode 100644 index 00000000..b8f46b71 --- /dev/null +++ b/Assets/ui_tabdesel.svg @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/Assets/ui_tabempty.svg b/Assets/ui_tabempty.svg new file mode 100644 index 00000000..9697edbe --- /dev/null +++ b/Assets/ui_tabempty.svg @@ -0,0 +1,82 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/Assets/ui_tabsel.svg b/Assets/ui_tabsel.svg new file mode 100644 index 00000000..9fb2e1cb --- /dev/null +++ b/Assets/ui_tabsel.svg @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/Assets/ui_toggle_off.svg b/Assets/ui_toggle_off.svg new file mode 100644 index 00000000..d5994c54 --- /dev/null +++ b/Assets/ui_toggle_off.svg @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/Assets/ui_toggle_on.svg b/Assets/ui_toggle_on.svg new file mode 100644 index 00000000..a04e1bb8 --- /dev/null +++ b/Assets/ui_toggle_on.svg @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/Documentation/EL_Manual.lyx b/Documentation/EL_Manual.lyx index 5ff7f21c..d2b3d54e 100644 --- a/Documentation/EL_Manual.lyx +++ b/Documentation/EL_Manual.lyx @@ -5460,6 +5460,187 @@ ELExtractor \begin_layout Standard Extracts resources from the environment. + Note that +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +ELExtractor +\end_layout + +\end_inset + + works with both the stock resource system and with Kethane (auto-detected + if installed). + Can (with a little work +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +Currently, this would require modifying EL's source to search for implementers + of IResourceProvider instead of simply adding the stock and Kethane (if + installed) providers. +\end_layout + +\end_inset + +) be extended to support other resource providers. + All supported providers are treated equally in that the amount of resource + extracted from a provider is based on that provider's contribution to the + available resource at the location of extractor part's ground-hit location. + For example with Kethane installed, EL's auger will extract +\noun on +MetalOre +\noun default + from a Kethane deposit at a rate slightly lower than specified by +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Rate +\end_layout + +\end_inset + + in the module files because the stock resource system will provide a certain + amount (based on concentration) as well, resulting in the total rate of + extraction being as specified, but if the auger misses a Kethane-based + deposit, the extraction rate will be determined by concentration multiplied + by the specified rate. +\end_layout + +\begin_layout Paragraph +Model Requirements +\end_layout + +\begin_layout Standard +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +ELExtractor +\end_layout + +\end_inset + + requires the model to have a head transform (goes into the ground) and + a tail transform (does not go into the ground). + The transforms are used to do a physics ray-cast to determine both whether + the extractor has ground contact and the exact location of that contact. + The head transform must be outside any colliders in order to allow it into + the ground (visual mesh that penetrates the ground poses no problem). + The tail transform may be either inside or outside any colliders, but inside + is recommended to ensure that it cannot go into the ground. + The transforms may be animated: the ray-cast is performed each frame. +\end_layout + +\begin_layout Paragraph +Part Requirements +\end_layout + +\begin_layout Standard +None. +\end_layout + +\begin_layout Paragraph +Module Fields +\end_layout + +\begin_layout Description +EVARange Adjust the range (in meters) from which an EVA kerbal can activate + or deactivate the extractor. + Default is +\begin_inset Formula $1.5m$ +\end_inset + +. +\end_layout + +\begin_layout Description +ResourceName The name of the resource to extract. + Required. +\end_layout + +\begin_layout Description +Rate The flow rate of the extractor, in +\begin_inset Formula $u/s$ +\end_inset + + (resource units/second). + Defaults to +\begin_inset Formula $0$ +\end_inset + +. +\end_layout + +\begin_layout Description +flowMode How the extracted resource is distributed through the extractor + vessel. + Defaults to +\noun on + +\begin_inset Flex Code +status open + +\begin_layout Plain Layout + +\noun on +ALL_VESSEL +\end_layout + +\end_inset + +. +\end_layout + +\begin_layout Description +HeadTransform The name of the model transform used as the target of the + ray-cast used to detect ground contact. + This is the point of the model that needs to be in the ground for the part + to be considered in contact with the ground. +\end_layout + +\begin_layout Description +TailTransform The name of the model transform used as the source of the + ray-cast used to detect ground contact. + This is the point of the model that needs to be out of the ground for the + part to be considered in contact with the ground. +\end_layout + +\begin_layout Description +INPUT_RESOURCE{} Note that this is a node. + This is as per the stock resource extraction module ( +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +ELExtractor +\end_layout + +\end_inset + + is derives from +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +BaseDrill +\end_layout + +\end_inset + +, so many of +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +BaseDrill +\end_layout + +\end_inset + +'s fields and nodes are relevant). \end_layout \begin_layout Subsubsection @@ -6628,26 +6809,32 @@ Resources \end_layout \begin_layout Verbatim + EL_Recipe { \end_layout \begin_layout Verbatim + structure = 5 \end_layout \begin_layout Verbatim + Resources { \end_layout \begin_layout Verbatim + RocketParts = 1 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + } \end_layout @@ -6746,30 +6933,37 @@ literal "true" \end_layout \begin_layout Verbatim + EL_ModuleRecipe { \end_layout \begin_layout Verbatim + name = KerbalEVA \end_layout \begin_layout Verbatim + Resources { \end_layout \begin_layout Verbatim + Metal = 39 \end_layout \begin_layout Verbatim + loss = 44.75 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + } \end_layout @@ -6794,14 +6988,17 @@ EL_DefaultStructureRecipe \begin_deeper \begin_layout Verbatim + EL_DefaultStructureRecipe { \end_layout \begin_layout Verbatim + RocketParts = 1 \end_layout \begin_layout Verbatim + } \end_layout @@ -6929,26 +7126,32 @@ literal "true" \begin_deeper \begin_layout Verbatim + EL_ResourceRecipe { \end_layout \begin_layout Verbatim + name = Ablator \end_layout \begin_layout Verbatim + Resources { \end_layout \begin_layout Verbatim + RocketParts = 1 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + } \end_layout @@ -7227,30 +7430,37 @@ literal "true" \begin_deeper \begin_layout Verbatim + EL_RecycleRecipe { \end_layout \begin_layout Verbatim + name = RocketParts \end_layout \begin_layout Verbatim + Resources { \end_layout \begin_layout Verbatim + ScrapMetal = 9 \end_layout \begin_layout Verbatim + loss = 1 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + } \end_layout @@ -7335,26 +7545,32 @@ literal "true" \begin_deeper \begin_layout Verbatim + EL_TransferRecipe { \end_layout \begin_layout Verbatim + name = RocketParts \end_layout \begin_layout Verbatim + Resources { \end_layout \begin_layout Verbatim + RocketParts = 1 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + } \end_layout @@ -7439,34 +7655,42 @@ literal "true" \begin_deeper \begin_layout Verbatim + EL_KerbalRecipe { \end_layout \begin_layout Verbatim + structure = 10 \end_layout \begin_layout Verbatim + KerbalEVA = 83.75 \end_layout \begin_layout Verbatim + Resources { \end_layout \begin_layout Verbatim + Kethane = 30 \end_layout \begin_layout Verbatim + loss = -29 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + } \end_layout @@ -7567,110 +7791,137 @@ efficiency \end_layout \begin_layout Verbatim + EL_ConverterRecipe { \end_layout \begin_layout Verbatim + name = LFOFiredSmelter \end_layout \begin_layout Verbatim + Input { \end_layout \begin_layout Verbatim + efficiency = 1 \end_layout \begin_layout Verbatim + LFOMix = 864.49048 -5186.94288 \end_layout \begin_layout Verbatim + MetalOre = 1596.882 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + Output { \end_layout \begin_layout Verbatim + efficiency = 1 \end_layout \begin_layout Verbatim + CarbonDioxide = 1056.228 \end_layout \begin_layout Verbatim + Water = 288.24448 \end_layout \begin_layout Verbatim + Metal = 1116.9 -9627.678 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + Input { \end_layout \begin_layout Verbatim + efficiency = 0 \end_layout \begin_layout Verbatim + LFOMix = 864.49048 -5186.94288 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + Output { \end_layout \begin_layout Verbatim + efficiency = 0 \end_layout \begin_layout Verbatim + Carbon = 24.0214 \end_layout \begin_layout Verbatim + CarbonDioxide = 176.038 \end_layout \begin_layout Verbatim + CarbonMonoxide = 476.1717 \end_layout \begin_layout Verbatim + Formaldehyde = 30.02598 \end_layout \begin_layout Verbatim + Hydrogen = 14.11116 \end_layout \begin_layout Verbatim + Water = 144.12224 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + } \end_layout @@ -7679,34 +7930,113 @@ EL_ConverterRecipe { \end_layout \begin_layout Verbatim + EL_ResourceRecipe { \end_layout \begin_layout Verbatim + name = LFOMix \end_layout \begin_layout Verbatim + Resources { \end_layout \begin_layout Verbatim + LiquidFuel = 9 \end_layout \begin_layout Verbatim + Oxidizer = 11 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + } \end_layout \end_deeper +\begin_layout Subsubsection +Other Recipes +\end_layout + +\begin_layout Description +EL_ResourceLink While not strictly a recipe, +\noun on +EL_ResourceLink +\noun default + is used for specifying resources that should be linked when setting up + resource transfer after building a new craft but before releasing it. + The node is very simple: a +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +name +\end_layout + +\end_inset + + line that names the link set (currently not used internally, but useful + for Module Manager patches), and a series of +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +resource +\end_layout + +\end_inset + + lines that specify the resources in the link set. + Any link sets with overlaps in their linked resources will result in undefined + behavior +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +rhinodamons +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Verbatim + +EL_ResourceLink { +\end_layout + +\begin_layout Verbatim + + name = RocketFuel +\end_layout + +\begin_layout Verbatim + + resource = LiquidFuel +\end_layout + +\begin_layout Verbatim + + resource = Oxidizer +\end_layout + +\begin_layout Verbatim + +} +\end_layout + \begin_layout Subsection Resource Rates \end_layout @@ -7791,38 +8121,47 @@ default \end_layout \begin_layout Verbatim + EL_ResourceRates { \end_layout \begin_layout Verbatim + default = 5 \end_layout \begin_layout Verbatim + ElectricCharge = 1 \end_layout \begin_layout Verbatim + LiquidFuel = 0.36 \end_layout \begin_layout Verbatim + Oxidizer = 0.44 \end_layout \begin_layout Verbatim + MonoPropellant = 0.4 \end_layout \begin_layout Verbatim + XenonGas = 2 \end_layout \begin_layout Verbatim + Ore = 8 \end_layout \begin_layout Verbatim + } \end_layout diff --git a/GameData/ExtraplanetaryLaunchpads/ELContractISRU.cfg b/GameData/ExtraplanetaryLaunchpads/ELContractISRU.cfg index 8b35b31c..4d9f8b08 100644 --- a/GameData/ExtraplanetaryLaunchpads/ELContractISRU.cfg +++ b/GameData/ExtraplanetaryLaunchpads/ELContractISRU.cfg @@ -6,20 +6,22 @@ { @PART_REQUEST:HAS[#Part[ISRU]] { + Part = ELLathe + Part = ELRocketBuilder Part = ELSmelter Part = ELSmallSmelter Part = ELTinySmelter - Part = ELRocketBuilder } } @Station { @PART_REQUEST:HAS[#Part[ISRU]] { + Part = ELLathe + Part = ELRocketBuilder Part = ELSmelter Part = ELSmallSmelter Part = ELTinySmelter - Part = ELRocketBuilder } } @Satellite diff --git a/GameData/ExtraplanetaryLaunchpads/EL_MM.cfg b/GameData/ExtraplanetaryLaunchpads/EL_MM.cfg index aba3126f..215db8a8 100644 --- a/GameData/ExtraplanetaryLaunchpads/EL_MM.cfg +++ b/GameData/ExtraplanetaryLaunchpads/EL_MM.cfg @@ -85,7 +85,7 @@ @name = ELExtendingLaunchClamp // The part is not meant to be placed directly. Rather, EL will do a // switch when loading the craft file. - @TechHidden = true + TechHidden = true @category = none -tags = cck-el @MODULE[LaunchClamp] { diff --git a/GameData/ExtraplanetaryLaunchpads/Parts/ConstructionDrone/depr-part.cfg b/GameData/ExtraplanetaryLaunchpads/Parts/ConstructionDrone/depr-part.cfg index 87e04f1f..7c9ebcd6 100644 --- a/GameData/ExtraplanetaryLaunchpads/Parts/ConstructionDrone/depr-part.cfg +++ b/GameData/ExtraplanetaryLaunchpads/Parts/ConstructionDrone/depr-part.cfg @@ -21,6 +21,7 @@ PART TechRequired = Unresearchable tags = deprecated category = none + TechHidden = True entryCost = 12200 cost = 227400 title = #EL_ELConstructionDrone_title // Construction Drone diff --git a/GameData/ExtraplanetaryLaunchpads/Parts/launchpad/part.cfg b/GameData/ExtraplanetaryLaunchpads/Parts/launchpad/part.cfg index e1a89ac0..dc6c3381 100644 --- a/GameData/ExtraplanetaryLaunchpads/Parts/launchpad/part.cfg +++ b/GameData/ExtraplanetaryLaunchpads/Parts/launchpad/part.cfg @@ -35,6 +35,7 @@ cost = 75000 TechRequired = Unresearchable tags = deprecated category = none +TechHidden = True title = #EL_ELLaunchpad_title // Launch Pad manufacturer = Kairyuu Shipping description = #EL_ELLaunchpad_desc // Build rockets off-planet! diff --git a/GameData/ExtraplanetaryLaunchpads/Parts/runway/part.cfg b/GameData/ExtraplanetaryLaunchpads/Parts/runway/part.cfg index 45eb9cb7..6b321890 100644 --- a/GameData/ExtraplanetaryLaunchpads/Parts/runway/part.cfg +++ b/GameData/ExtraplanetaryLaunchpads/Parts/runway/part.cfg @@ -32,6 +32,7 @@ tags = deprecated entryCost = 0 cost = 6000 category = none +TechHidden = True title = #EL_ELRunway_title // Runway manufacturer = Kairyuu Shipping description = #EL_ELRunway_desc // Build space planes off-planet! diff --git a/GameData/ExtraplanetaryLaunchpads/Resources/Recipes.cfg b/GameData/ExtraplanetaryLaunchpads/Resources/Recipes.cfg index ea49367c..111e8c05 100644 --- a/GameData/ExtraplanetaryLaunchpads/Resources/Recipes.cfg +++ b/GameData/ExtraplanetaryLaunchpads/Resources/Recipes.cfg @@ -59,7 +59,7 @@ EL_ConverterRecipe { // LiquidFuel is assumed to be RP-1 which is further assumed to be C12H16 // and thus is 160.25544g/mol // Oxidizer is assumed to be liquid oxygen (O2) and thus is 31.9988g/mol - // MetalOre or is assumed to be hematite (Fe2O3) which is 159.6882g/mol + // MetalOre is assumed to be hematite (Fe2O3) which is 159.6882g/mol // // The LiquidFuel + Oxidizer mix is assumed to be 2C12H16 + 17*O2 (this // gets pretty close to the correct volume ratios for RP-1+lox, and is @@ -177,6 +177,12 @@ EL_ConverterRecipe { } } +EL_ResourceLink { + name = RocketFuel + resource = LiquidFuel + resource = Oxidizer +} + EL_ConverterRecipe { name = MetalWorking Input { diff --git a/KodeUI b/KodeUI new file mode 160000 index 00000000..42d4f9b9 --- /dev/null +++ b/KodeUI @@ -0,0 +1 @@ +Subproject commit 42d4f9b96839b9f8868a69eb26a8d0cf597995f8 diff --git a/README.txt b/README.txt index e2e907c0..f969bfa1 100644 --- a/README.txt +++ b/README.txt @@ -64,7 +64,20 @@ Mods considered essential for getting the most out of EL: o Infernal Robotics. Makes it easier to move things around. http://forum.kerbalspaceprogram.com/threads/37707 -Please report all issues at https://github.com/taniwha-qf/Extraplanetary-Launchpads/issues +Please report all issues at +https://github.com/taniwha/Extraplanetary-Launchpads/issues Many resource containers use HexCans by Greys (https://github.com/Greys0/HexCans). + +Notes for building: +Note that EL depends on KodeUI: https://github.com/sarbian/KodeUI.git +However, KodeUI is included as a git submodule. Use + + git submodule init + git submodule update + +to get started and refer to the `git submodule --help` (or +https://git-scm.com/book/en/v2/Git-Tools-Submodules) for further +details. However, the tree has been set up to "just work" once +submodules have been updated. diff --git a/Source/BuildControl.cs b/Source/BuildControl.cs index c8c0e885..7b7e7642 100644 --- a/Source/BuildControl.cs +++ b/Source/BuildControl.cs @@ -29,6 +29,9 @@ namespace ExtraplanetaryLaunchpads { public class ELBuildControl : ELWorkSink { + public static readonly EventData onBuildStateChanged = new EventData ("onBuildStateChanged"); + public static readonly EventData onPadRenamed = new EventData ("onPadRenamed"); + public interface IBuilder { void Highlight (bool on); @@ -38,9 +41,6 @@ public interface IBuilder Transform PlaceShip (Transform shipTransform, Box vessel_bounds); void RepositionShip (Vessel ship); void PostBuild (Vessel craftVessel); - void PadSelection_start (); - void PadSelection (); - void PadSelection_end (); bool canBuild { get; } bool capture { get; } @@ -90,7 +90,14 @@ public RMResourceSet craftResources public bool craftBoMdirty { get; private set; } public CostReport buildCost { get; private set; } public CostReport builtStuff { get; private set; } - public State state { get; private set; } + State _state; + public State state { + get { return _state; } + private set { + _state = value; + onBuildStateChanged.Fire (this); + } + } public bool paused { get; private set; } public string KACalarmID = ""; @@ -108,6 +115,7 @@ public double productivity public DockedVesselInfo vesselInfo { get; private set; } public Part craftRoot { get; private set; } + ModuleGroundPart groundPartModule; public string craftName { get { @@ -157,13 +165,19 @@ public void UnCancelBuild () public void PauseBuild () { if (state == State.Building || state == State.Canceling) { - paused = true; + if (!paused) { + paused = true; + onBuildStateChanged.Fire (this); + } } } public void ResumeBuild () { - paused = false; + if (paused) { + paused = false; + onBuildStateChanged.Fire (this); + } } public bool isActive @@ -174,6 +188,11 @@ public bool isActive } } + static BuildResource FindResource (List reslist, string name) + { + return reslist.Where(r => r.name == name).FirstOrDefault (); + } + public double CalculateWork () { if (paused) { @@ -190,7 +209,7 @@ public double CalculateWork () } else if (state == State.Canceling) { for (int i = built.Count; i-- > 0; ) { var res = built[i]; - var cres = ELBuildWindow.FindResource (cost, res.name); + var cres = FindResource (cost, res.name); hours += res.kerbalHours * (cres.amount - res.amount); } } @@ -228,7 +247,7 @@ void SetPadMass () var cost = buildCost.required; foreach (var bres in built) { - var cres = ELBuildWindow.FindResource (cost, bres.name); + var cres = FindResource (cost, bres.name); mass += (cres.amount - bres.amount) * bres.density; } } @@ -316,7 +335,7 @@ int CountResources (List built, List cost) { int count = 0; foreach (var bres in built) { - var cres = ELBuildWindow.FindResource (cost, bres.name); + var cres = FindResource (cost, bres.name); if (cres.amount - bres.amount > 0) { count++; } @@ -346,7 +365,7 @@ private void DoWork_Cancel (double kerbalHours) did_work = false; foreach (var bres in built) { - var cres = ELBuildWindow.FindResource (cost, bres.name); + var cres = FindResource (cost, bres.name); double remaining = cres.amount - bres.amount; if (remaining <= 0) { continue; @@ -409,7 +428,7 @@ internal void SetupCraftResources (Vessel vsl) { Part rootPart = vsl.parts[0].localRoot; craftResourceManager = new RMResourceManager (vsl.parts, rootPart, - false, true); + false); foreach (var br in buildCost.optional) { var amount = craftResources.ResourceAmount (br.name); craftResources.TransferResource (br.name, -amount); @@ -475,6 +494,17 @@ private void CoupleWithCraft (Vessel craftVessel) public delegate void PostCaptureDelegate (); public PostCaptureDelegate PostCapture = () => { }; + void HookGroundPartPickup () + { + groundPartModule = craftRoot.FindModuleImplementing (); + if (groundPartModule != null) { + // craft with ModuleGroundPart should have only the one part as + // properly configured deployable parts do not allow attachment + // in the editor and KIS refuses to touch them + ELGroundPart.HookPickup (groundPartModule, this); + } + } + private IEnumerator CaptureCraft (Vessel craftVessel) { FlightGlobals.overrideOrbit = true; @@ -503,6 +533,7 @@ private IEnumerator CaptureCraft (Vessel craftVessel) builder.SetCraftMass (0); CoupleWithCraft (craftVessel); + HookGroundPartPickup (); state = State.Transfer; PostCapture (); } @@ -603,7 +634,7 @@ void RotateLaunchClamps (ShipConstruct ship) elc[j].RotateTower (); } if (elc.Count < 1) { - if (p.Modules["ModuleRestockLaunchClamp"] != null) { + if (p.Modules.GetModule("ModuleRestockLaunchClamp") != null) { p.SendMessage("RotateTower", SendMessageOptions.DontRequireReceiver); } } @@ -624,7 +655,7 @@ void EnableExtendingLaunchClamps (ShipConstruct ship) // ReplaceLaunchClamps will not do any replacement because // the module uses a different name. Thus this will pick up // the ReStock module. - var lc = p.Modules["ModuleRestockLaunchClamp"]; + var lc = p.Modules.GetModule("ModuleRestockLaunchClamp"); if (lc != null) { (lc as LaunchClamp).EnableExtension (); } @@ -755,7 +786,8 @@ public bool CreateBoM () str = craftConfig.GetValue ("description"); if (!string.IsNullOrEmpty (str)) { - craftBoM.Add (Localizer.Format(str)); + str = Localizer.Format(str).Replace ('¨', '\n'); + craftBoM.Add (str); craftBoM.Add (""); // blank line } foreach (var part in craftConfig.GetNodes ("PART")) { @@ -837,12 +869,13 @@ void FindVesselResources () //Debug.Log ($"[ELBuildControl] FindVesselResources pad {pad_parts.Count} craft {craft_parts.Count}"); string vesselName = builder.vessel.vesselName; - Part root = builder.part.localRoot; + Part vesselRoot = builder.part.localRoot; //Debug.Log ($"[ELBuildControl] FindVesselResources pad"); padResourceManager = new RMResourceManager (vesselName, - pad_parts, root, + pad_parts, + vesselRoot, craft_parts, - false, true); + false); if (craft_parts.Count > 0) { //Debug.Log ($"[ELBuildControl] FindVesselResources craft"); @@ -850,7 +883,7 @@ void FindVesselResources () craft_parts, craftRoot, null, - false, true); + false); } } @@ -889,11 +922,12 @@ public void Load (ConfigNode node) } if (node.HasValue ("state")) { var s = node.GetValue ("state"); - state = (State) Enum.Parse (typeof (State), s); - if (state == State.Dewarping) { + _state = (State) Enum.Parse (typeof (State), s); + if (_state == State.Dewarping) { // The game got saved while the Dewarping state was still // active. Rather than restarting the dewarp coroutine, // Just jump straight to the Complete state. + // DO want to fire the state for switch to Complete state = State.Complete; } } @@ -921,12 +955,15 @@ public ELBuildControl (IBuilder builder) internal void OnStart () { workNet = builder.vessel.FindVesselModuleImplementing (); + GameEvents.onPartUnpack.Add (onPartUnpack); GameEvents.onVesselWasModified.Add (onVesselWasModified); GameEvents.onPartDie.Add (onPartDie); if (vesselInfo != null) { craftRoot = builder.vessel[vesselInfo.rootPartUId]; if (craftRoot == null) { CleanupAfterRelease (); + } else { + HookGroundPartPickup (); } } PlaceCraftHull (); @@ -963,14 +1000,38 @@ void DestroyCraftHull () internal void OnDestroy () { + GameEvents.onPartUnpack.Remove (onPartUnpack); GameEvents.onVesselWasModified.Remove (onVesselWasModified); GameEvents.onPartDie.Remove (onPartDie); DestroyCraftHull (); } + IEnumerator WaitAndStopCoroutines (MonoBehaviour behavior) + { + yield return null; + behavior.StopAllCoroutines (); + } + + void onPartUnpack (Part p) + { + if (p != builder.part) { + return; + } + if (groundPartModule != null) { + var b = builder as PartModule; + b.StartCoroutine (WaitAndStopCoroutines (groundPartModule)); + } + } + + public void OnRename (string oldName) + { + onPadRenamed.Fire (this, oldName, builder.Name); + } + void CleanupAfterRelease () { craftRoot = null; + groundPartModule = null; vesselInfo = null; builtStuff = null; // ensure pad mass gets reset SetPadMass (); @@ -978,14 +1039,24 @@ void CleanupAfterRelease () DestroyCraftHull (); } - public void ReleaseVessel () + IEnumerator WaitAndSwitchVessel (Vessel vessel) + { + for (int count = 15; count-- > 0; ) { + yield return null; + } + FlightGlobals.ForceSetActiveVessel (vessel); + } + + public void ReleaseVessel (bool switchVessel = true) { TransferResources (); craftRoot.Undock (vesselInfo); var vesselCount = FlightGlobals.Vessels.Count; Vessel vsl = FlightGlobals.Vessels[vesselCount - 1]; - FlightGlobals.ForceSetActiveVessel (vsl); - //builder.part.StartCoroutine (FixAirstreamShielding (vsl)); + if (switchVessel) { + (builder as PartModule).StartCoroutine (WaitAndSwitchVessel (vsl)); + } + vsl.StartCoroutine (FixAirstreamShielding (vsl)); CleanupAfterRelease (); } @@ -1040,6 +1111,35 @@ void SanitizePart(Part part) { } } + void RemoveFX(Part part) + { + for (int i = part.fxGroups.Count; i-- > 0; ) { + var group = part.fxGroups[i]; + for (int j = group.fxEmittersNewSystem.Count; j-- > 0; ) { + var psys = group.fxEmittersNewSystem[j]; + if (psys && psys.gameObject) { + UnityEngine.Object.Destroy (psys.gameObject); + } + } + group.fxEmittersNewSystem.Clear(); + for (int j = group.lights.Count; j-- > 0; ) { + var light = group.lights[j]; + if (light && light.gameObject) { + UnityEngine.Object.Destroy (light.gameObject); + } + } + group.lights.Clear(); + if (group.sfx) { + UnityEngine.Object.Destroy (group.sfx); + group.sfx = null; + } + if (group.audio) { + UnityEngine.Object.Destroy (group.audio); + group.audio = null; + } + } + } + public CostReport getBuildCost (ConfigNode craft, string craftText = null) { lockedParts = false; @@ -1063,6 +1163,7 @@ public CostReport getBuildCost (ConfigNode craft, string craftText = null) craftVessel.Initialize (true); SetCraftOrbit (craftVessel, OrbitDriver.UpdateMode.IDLE); foreach (Part part in craftVessel.parts) { + RemoveFX(part); SanitizePart(part); part.ModulesOnStart(); } diff --git a/Source/DisposablePad/DisposablePad.cs b/Source/DisposablePad/DisposablePad.cs index 1c92fe8a..b8b547ce 100644 --- a/Source/DisposablePad/DisposablePad.cs +++ b/Source/DisposablePad/DisposablePad.cs @@ -24,12 +24,13 @@ You should have received a copy of the GNU General Public License namespace ExtraplanetaryLaunchpads { - public class ELDisposablePad : PartModule, IModuleInfo, IPartMassModifier, ELBuildControl.IBuilder, ELControlInterface, ELWorkSink, ELRenameWindow.IRenamable + public class ELDisposablePad : PartModule, IModuleInfo, IPartMassModifier, ELBuildControl.IBuilder, ELControlInterface, ELWorkSink, ELRenameDialog.IRenamable { [KSPField (isPersistant = false)] public string SpawnTransform; [KSPField (isPersistant = true, guiActive = true, guiName = "Pad name")] public string PadName = ""; + string oldName = ""; [KSPField (isPersistant = true)] public bool Operational = true; @@ -245,6 +246,9 @@ public void SetShipTransform (Transform shipTransform, Part rootPart) var pos = Vector3.zero; if (n != null) { Vector3 nodeAxis = rootXform.TransformDirection(n.orientation); + if (n.id == "KISMount") { + nodeAxis = -nodeAxis; + } Vector3 forward = rootXform.forward; float fwdDot = Vector3.Dot (forward, nodeAxis); Debug.Log ($"[EL] nodeAxis: {nodeAxis}"); @@ -324,6 +328,7 @@ public override void OnStart (PartModule.StartState state) EL_Utils.SetupEVAEvent (Events["ShowRenameUI"], EVARange); } control.OnStart (); + UpdateMenus (false); } void OnDestroy () @@ -336,21 +341,21 @@ void OnDestroy () [KSPEvent (guiActive = true, guiName = "Hide UI", active = false)] public void HideUI () { - ELBuildWindow.HideGUI (); + ELWindowManager.HideBuildWindow (); } [KSPEvent (guiActive = true, guiName = "Show UI", active = false)] public void ShowUI () { - ELBuildWindow.ShowGUI (); - ELBuildWindow.SelectPad (control); + ELWindowManager.ShowBuildWindow (control); } [KSPEvent (guiActive = true, guiActiveEditor = true, guiName = "Rename", active = true)] public void ShowRenameUI () { - ELRenameWindow.ShowGUI (this); + oldName = PadName; + ELRenameDialog.OpenDialog (ELLocalization.RenameMicropad, this); } public void UpdateMenus (bool visible) @@ -388,7 +393,7 @@ public double CalculateWork () public void OnRename () { - ELBuildWindow.updateCurrentPads (); + control.OnRename (oldName); } } } diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs new file mode 100644 index 00000000..3b52e942 --- /dev/null +++ b/Source/Editor/Editor.cs @@ -0,0 +1,450 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +namespace ExtraplanetaryLaunchpads { + + public class ELEditor : MonoBehaviour + { + const BindingFlags bindFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; + /** Delegate for Update and normal Start + */ + delegate void UpdateDelegate (); + /** Delegate for coroutine Start + */ + delegate IEnumerator StartDelegate (); + + static ELEditor editor; + static FieldInfo rootPart; + + ShipConstruct ship; + + /** Disabled instance of the VAB/SPH editor so that part modules can + * get at \a ship when they need to. + */ + EditorLogic fakeEditor; + + List Updaters; + List FixedUpdaters; + List LateUpdaters; + // for Part.Start and any modules that use a coroutine Start + List CRStarters; + // For any other modules + List Starters; + + bool ready; + + void Awake () + { + Updaters = new List (); + FixedUpdaters = new List (); + LateUpdaters = new List (); + CRStarters = new List (); + Starters = new List (); + + rootPart = typeof(EditorLogic).GetField ("rootPart", bindFlags); + editor = this; + } + + void OnDestroy () + { + editor = null; + } + + void OnDisable () + { + Debug.Log ($"[ELEditor] OnDisable"); + + Updaters.Clear (); + FixedUpdaters.Clear (); + LateUpdaters.Clear (); + CRStarters.Clear (); + Starters.Clear (); + + ready = false; + + // Remove the fake EditorLogic so it doesn't cause problems the + // next time the player goes to the VAB or SPH + if (fakeEditor) { + Destroy (fakeEditor.gameObject); + } + fakeEditor = null; + } + + /** Simple wrapper to create a delegate for update or normal Start + */ + UpdateDelegate CreateUpdateDelegate (MonoBehaviour module, MethodInfo method) + { + return (UpdateDelegate) Delegate.CreateDelegate (typeof (UpdateDelegate), module, method); + } + + /** Simple wrapper to create a delegate for coroutine Start + */ + StartDelegate CreateStartDelegate (MonoBehaviour module, MethodInfo method) + { + return (StartDelegate) Delegate.CreateDelegate (typeof (StartDelegate), module, method); + } + + /** Find the start method and add it to the appropriate list. + * + * Unity supports coroutine Start() (return IEnumerator instead of void) + * so need to check the return time. + */ + void FindStart (MonoBehaviour module) + { + var type = module.GetType (); + var start = type.GetMethod ("Start", bindFlags); + if (start == null) { + // many a PartModule relies on OnStart (called indirectly by + // Part.Start) rather than Start + return; + } + if (start.ReturnType == typeof(void)) { + // Strt is a normal (void) method + var del = CreateUpdateDelegate (module, start); + Starters.Add (del); + } else { + // Start is a coroutine + var del = CreateStartDelegate (module, start); + CRStarters.Add (del); + } + } + + /** Find the named update method and add a delegate to the list. + */ + void FindUpdater (MonoBehaviour module, string name, List updaters) + { + var type = module.GetType (); + var update = type.GetMethod (name, bindFlags); + if (update == null) { + // Not all modules implement all updaters (some don't impement + // any) + return; + } + var del = CreateUpdateDelegate (module, update); + updaters.Add (del); + } + + void RemoveUpdaters (object target, List updaters) + { + for (int i = updaters.Count; i-- > 0; ) { + if (updaters[i].Target == target) { + updaters.RemoveAt (i); + } + } + } + + void RemoveUpdaters (object target) + { + RemoveUpdaters (target, Updaters); + RemoveUpdaters (target, FixedUpdaters); + RemoveUpdaters (target, LateUpdaters); + } + + /** Run all the collected Start methods. + * + * Both Starters and CRStarters will be empty on completion. + */ + void RunStarters () + { + SetEditorScene (); + + // run through all the simple starters first + for (int i = Starters.Count; i-- > 0; ) { + var mod = Starters[i].Target as MonoBehaviour; + mod.enabled = true; + try { + Starters[i] (); + } catch (Exception e) { + Debug.LogError ($"[ELEditor] caught Start exception: {e.Message}\n{e.StackTrace}"); + Debug.LogError ($" on {Starters[i].Target}"); + } + if (!mod.enabled) { + // the module (probably PartModule, but...) disabled itself + //Debug.Log ($"[ELEditor] {Starters[i].Target} disabled itself"); + RemoveUpdaters (Starters[i].Target); + } + mod.enabled = false; + // These are one-shot methods, so remove as we go + Starters.RemoveAt (i); + } + + Debug.Log ($"[ELEditor] RunStarters: running coroutine Start"); + // run through all the coroutine starters + var starters = new List (); + for (int i = 0; i < CRStarters.Count; i++) { + starters.Add (CRStarters[i] ()); + } + for (int i = ship.parts.Count; i-- > 0; ) { + Part p = ship.parts[i]; + for (int j = p.Modules.Count; j-- > 0; ) { + p.Modules[j].enabled = true; + } + } + while (CRStarters.Count > 0) { + for (int i = CRStarters.Count; i-- > 0; ) { + bool remove = false; + var mod = CRStarters[i].Target as MonoBehaviour; + mod.enabled = true; + try { + remove = !starters[i].MoveNext (); + } catch (Exception e) { + Debug.LogError ($"[ELEditor] caught Start exception: {e.Message}\n{e.StackTrace}"); + Debug.LogError ($" on {CRStarters[i].Target}"); + Debug.LogError ($" Disabling {starters[i]} ({CRStarters[i]})"); + remove = true; + } + if (!mod.enabled) { + // the module (probably PartModule, but...) disabled + // itself + //Debug.Log ($"[ELEditor] {CRStarters[i].Target} disabled itself"); + RemoveUpdaters (CRStarters[i].Target); + remove = true; + } + mod.enabled = false; + if (remove) { + starters.RemoveAt (i); + CRStarters.RemoveAt (i); + } + } + } + for (int i = ship.parts.Count; i-- > 0; ) { + Part p = ship.parts[i]; + for (int j = p.Modules.Count; j-- > 0; ) { + PartModule m = p.Modules[j]; + + if (!m.enabled) { + //Debug.Log ($"[ELEditor] {m} disabled itself"); + RemoveUpdaters (m); + } + + m.enabled = false; + } + } + Debug.Log ($"[ELEditor] RunStarters: end coroutine Start"); + + RestoreScene (); + + ready = true; + } + + void DisableCoroutines () + { + for (int i = ship.parts.Count; i-- > 0; ) { + Part p = ship.parts[i]; + p.StopAllCoroutines (); + for (int j = p.Modules.Count; j-- > 0; ) { + PartModule m = p.Modules[j]; + m.StopAllCoroutines (); + } + } + } + + IEnumerator WaitAndRunStarters () + { + yield return null; + RunStarters (); + DisableCoroutines (); + } + + void SetupEditor (ShipConstruct ship) + { + this.ship = ship; + + Debug.Log ($"[ELEditor] SetupEditor"); + + var go = new GameObject ("Fake Editor"); + go.transform.SetParent (transform, false); + + fakeEditor = go.AddComponent (); + // Do not want KSP's EditorLogic to run, it's needed only to hold + // ShipConstruct and any other necessary references so PartModules + // can run thinking they are in the editor. + fakeEditor.enabled = false; + + fakeEditor.ship = ship; + Part root = ship.parts[0].localRoot; + rootPart.SetValue (fakeEditor, ship.parts[0].localRoot); + + var nfo = new GameObject ("FakeNameField", typeof (TMP_InputField)); + nfo.transform.SetParent (go.transform, false); + nfo.SetActive (false); + var fnf = nfo.GetComponent (); + fakeEditor.shipNameField = fnf; + fakeEditor.shipDescriptionField = fnf; + + var bo = new GameObject ("FakeButton", + typeof (Button), + typeof (FlagBrowserButton), + typeof (KSP.UI.UIOnClick)); + bo.transform.SetParent (go.transform, false); + bo.SetActive (false); + var fb = bo.GetComponent