diff options
Diffstat (limited to 'src/koopatlas')
| -rw-r--r-- | src/koopatlas/hud.cpp | 630 | ||||
| -rw-r--r-- | src/koopatlas/hud.h | 69 | ||||
| -rw-r--r-- | src/koopatlas/mapdata.cpp | 16 | ||||
| -rw-r--r-- | src/koopatlas/mapdata.h | 17 | ||||
| -rw-r--r-- | src/koopatlas/pathmanager.cpp | 69 | ||||
| -rw-r--r-- | src/koopatlas/pathmanager.h | 2 | ||||
| -rw-r--r-- | src/koopatlas/shop.cpp | 22 | ||||
| -rw-r--r-- | src/koopatlas/starcoin.cpp | 26 | 
8 files changed, 503 insertions, 348 deletions
diff --git a/src/koopatlas/hud.cpp b/src/koopatlas/hud.cpp index 44b0fce..90e769e 100644 --- a/src/koopatlas/hud.cpp +++ b/src/koopatlas/hud.cpp @@ -1,25 +1,143 @@  #include "koopatlas/hud.h" -void CharToWChar(const char *input, wchar_t *output, int length) { for (int i = 0; i < length; i++) output[i] = input[i]; } -int getStarCoinCount() { +dTexMapColouriser_c::dTexMapColouriser_c() { +	texmap = 0; +	original = 0; +	mine = 0; +} -	SaveBlock *save = GetSaveFile()->GetBlock(-1); -	int coinsSpent = save->credits_hiscore; -	int coinsEarned = 0; +void *EGG__Heap__alloc(unsigned long size, int unk, void *heap); +void EGG__Heap__free(void *ptr, void *heap); -	for (int w = 0; w < 10; w++) { -		for (int l = 0; l < 10; l++) { -			u32 conds = save->GetLevelCondition(w, l); +dTexMapColouriser_c::~dTexMapColouriser_c() { +	resetAndClear(); +} -			if (conds & COND_COIN1) { coinsEarned++; } -			if (conds & COND_COIN2) { coinsEarned++; } -			if (conds & COND_COIN3) { coinsEarned++; } -		} +void dTexMapColouriser_c::resetAndClear() { +	texmap = 0; +	if (mine) { +		EGG__Heap__free(mine, 0); +		mine = 0; +	} +} + +void dTexMapColouriser_c::setTexMap(nw4r::lyt::TexMap *tm) { +	OSReport("Colourising TexMap: %p (w:%d h:%d)\n", tm, tm->width, tm->height); +	if (texmap) +		resetAndClear(); + +	if (tm->mBits.textureFormat != GX_TF_IA8) { +		OSReport("Warning: Trying to colourise image whose format is %d not GX_TF_IA8\n", tm->mBits.textureFormat);  	} -	int coinsLeft = coinsEarned - coinsSpent; -	return coinsLeft; +	texmap = tm; +	original = (u16*)tm->image; +	mine = (u16*)EGG__Heap__alloc(tm->width * tm->height * 4, 0x20, mHeap::gameHeaps[2]); +	tm->image = mine; +	tm->mBits.textureFormat = GX_TF_RGBA8; +} + +void dTexMapColouriser_c::applyAlso(nw4r::lyt::TexMap *tm) { +	if (!texmap) { +		setTexMap(tm); +	} else { +		tm->image = mine; +		tm->mBits.textureFormat = GX_TF_RGBA8; +	} +} + +inline static float hslValue(float n1, float n2, float hue) { +	if (hue > 6.0f) +		hue -= 6.0f; +	else if (hue < 0.0f) +		hue += 6.0f; + +	if (hue < 1.0f) +		return n1 + (n1 - n1) * hue; +	else if (hue < 3.0f) +		return n2; +	else if (hue < 4.0f) +		return n1 + (n2 - n1) * (4.0f - hue); +	else +		return n1; +} + +void dTexMapColouriser_c::colourise(int h, int s, int l) { +	if (!mine) +		return; + +	int width = texmap->width, height = texmap->height; +	int texelW = width / 4, texelH = height / 4; + +	u16 *source = original, *dest = mine; + +	float hueParam = h / 360.0f; +	float satParam = s / 100.0f; +	float lumParam = l / 100.0f; + +	for (int texelY = 0; texelY < texelH; texelY++) { +		for (int texelX = 0; texelX < texelW; texelX++) { +			for (int y = 0; y < 4; y++) { +				for (int x = 0; x < 4; x++) { +					u8 intensity = *source & 0xFF; +					u8 alpha = *source >> 8; + +					u8 r, g, b; + +					// This is a hack +					if (alpha < 250) { +						r = g = b = intensity; +					} else { +						// converting from GIMP's colourise code... +						// h and s are always the same +						// l is the only thing we need to touch: +						// we get the luminance from the source pixel +						// (which, conveniently, is the intensity) +						// manipulate it using the passed l and then +						// convert the whole thing to RGB + +						float lum = intensity / 255.0f; + +						// manipulate it +						if (l > 0) { +							lum = lum * (1.0f - lumParam); +							lum += (1.0f - (1.0f - lumParam)); +						} else if (l < 0) { +							lum = lum * (lumParam + 1.0f); +						} + +						// make it RGB + +						if (s == 0) { +							r = g = b = lum*255.0f; +						} else { +							float m1, m2; +							if (lum <= 0.5f) +								m2 = lum * (1.0f + satParam); +							else +								m2 = lum + satParam - lum * satParam; + +							m1 = 2.0f * lum - m2; + +							r = hslValue(m1, m2, hueParam * 6.0f + 2.0) * 255.0f; +							g = hslValue(m1, m2, hueParam * 6.0f) * 255.0f; +							b = hslValue(m1, m2, hueParam * 6.0f - 2.0) * 255.0f; +						} +					} + +					// now write it +					dest[0] = (alpha<<8)|r; +					dest[16] = (g<<8)|b; + +					source++; +					dest++; +				} +			} + +			dest += 16; +		} +	}  } @@ -37,27 +155,22 @@ dWMHud_c *dWMHud_c::build() {  dWMHud_c::dWMHud_c() {  	layoutLoaded = false; +	displayedControllerType = -1;  } +enum WMHudAnimation { +	SHOW_LIVES = 0, +	SHOW_HEADER, +	SHOW_FOOTER +}; -// TODO: Need to define these in a better way, somehow -#define ANIM_BUTTON_1 0 -#define ANIM_BUTTON_2 1 -#define ANIM_BOTTOM_SHOW 2 -#define ANIM_BOTTOM_HIDE 3 -#define ANIM_TOP_SHOW 4 -#define ANIM_TOP_HIDE 5  int dWMHud_c::onCreate() {  	if (!layoutLoaded) { -		bool gotFile = layout.loadArc("maphud.arc", false); +		bool gotFile = layout.loadArc("MapHUD.arc", false);  		if (!gotFile)  			return false; -		//static const char *brlanNames[3] = {"maphud_hitbutton.brlan", "maphud_in.brlan", "maphud_out.brlan"}; -		static const char *brlanNames[5] = {"maphud_hitbutton.brlan", "bottom_in.brlan", "bottom_out.brlan", "top_in.brlan", "top_out.brlan"}; -		static const char *groupNames[6] = {"B01_Button", "B02_Button", "A00_Window", "A00_Window", "A01_Window", "A01_Window"}; -  		bool output = layout.build("maphud.brlyt");  		if (!IsWideScreen()) { @@ -70,19 +183,62 @@ int dWMHud_c::onCreate() {  			layout.layout.rootPane->scale.y = 0.7711f;  		} -		layout.loadAnimations(brlanNames, 5); -		layout.loadGroups(groupNames, (int[6]){0, 0, 1, 2, 3, 4}, 6); -		layout.disableAllAnimations(); -		layout.enableNonLoopAnim(ANIM_BOTTOM_SHOW); +		static const char *brlanNames[2] = {"MapHUD_ShowMain.brlan", "MapHUD_ShowHeader.brlan"}; +		static const char *groupNames[3] = {"G_Lives", "G_Header", "G_Footer"}; -		hidePointBar(); -		setWorldText(" "); -		setWorldName(); +		layout.loadAnimations(brlanNames, 2); +		layout.loadGroups(groupNames, (int[3]){0, 1, 0}, 3); +		layout.disableAllAnimations(); -		if (dScKoopatlas_c::instance->pathManager.mustComplainToMapCreator) -			dWMHud_c::instance->setLevelText("Please Fix Your Missing Entrance. Thanks"); +		layout.enableNonLoopAnim(SHOW_LIVES); +		layout.enableNonLoopAnim(SHOW_FOOTER); +		layout.resetAnim(SHOW_HEADER); + +		static const char *tbNames[2] = {"MenuButtonInfo", "ItemsButtonInfo"}; +		layout.setLangStrings(tbNames, (int[2]){12, 15}, 4, 2); + +		static const char *paneNames[] = { +			"N_IconPos1P_00", "N_IconPos2P_00", +			"N_IconPos3P_00", "N_IconPos4P_00" +		}; +		layout.getPanes(paneNames, &N_IconPosXP_00[0], 4); + +		static const char *pictureNames[] = { +			"Header_Centre", "Header_Right", "Footer", +			"NormalExitFlag", "SecretExitFlag", +			"StarCoinOn0", "StarCoinOn1", "StarCoinOn2", +			"P_marioFace_00", "P_luigiFace_00", +			"P_BkinoFace_00", "P_YkinoFace_00" +		}; +		layout.getPictures(pictureNames, &Header_Centre, 12); + +		static const char *textBoxNames[] = { +			"LevelName", "LevelNameS", +			"LevelNumber", "LevelNumberS", +			"WorldName", "WorldNameS", +			"StarCoinCounter", +			"T_lifeNumber_00", "T_lifeNumber_01", +			"T_lifeNumber_02", "T_lifeNumber_03" +		}; +		layout.getTextBoxes(textBoxNames, &LevelName, 11); + +		headerCol.setTexMap(Header_Right->material->texMaps); +		headerCol.applyAlso(Header_Centre->material->texMaps); +		footerCol.setTexMap(Footer->material->texMaps);  		layoutLoaded = true; + +		layout.drawOrder = 0; + +		willShowHeader = false; +		willShowFooter = false; + +		loadFooterInfo(); + +		if (!dScKoopatlas_c::instance->pathManager.isMoving) +			enteredNode(); + +		setupLives();  	}  	return true; @@ -90,15 +246,37 @@ int dWMHud_c::onCreate() {  int dWMHud_c::onDelete() { +	dWMHud_c::instance = 0; + +	if (!layoutLoaded) +		return true; +  	return layout.free();  }  int dWMHud_c::onExecute() { -	updateLives(); -	setWorldName(); -	checkPointStatus(); -	setPointName(); +	if (!layoutLoaded) +		return true; + +	if (willShowHeader && (!(layout.isAnimOn(SHOW_HEADER)))) { +		willShowHeader = false; +		loadHeaderInfo(); +		playShowAnim(SHOW_HEADER); +	} + +	if (willShowFooter && (!(layout.isAnimOn(SHOW_FOOTER)))) { +		willShowFooter = false; +		loadFooterInfo(); +		playShowAnim(SHOW_FOOTER); +	} + +	setupLives(); // FUCK IT +	updatePressableButtonThingies(); + +	int scCount = getStarCoinCount(); +	int scLength = 3; +	WriteNumberToTextBox(&scCount, &scLength, StarCoinCounter, false);  	layout.execAnimations();  	layout.update(); @@ -108,303 +286,207 @@ int dWMHud_c::onExecute() {  int dWMHud_c::onDraw() { +	if (!layoutLoaded) +		return true; +  	layout.scheduleForDrawing();  	return true;  } -void dWMHud_c::updateLives() { - -	static const char *textID[4] = {"M", "L", "B", "Y"}; -	static const char *picID[4] = {"P_mariopic", "P_luigipic", "P_toadBlue", "P_toadyellow"}; - -	for (int i = 0; i < 4; i++) { -		char boxName [13]; -		sprintf(boxName, "T_%slifes_01", textID[i]); -		nw4r::lyt::TextBox *box = layout.findTextBoxByName(boxName); -		nw4r::lyt::Pane *pic = layout.findPictureByName(picID[i]); -		if (Player_Active[i] != 0) { -			box->alpha = 0xFF; -			pic->alpha = 0xFF; +void dWMHud_c::playShowAnim(int id) { +	if (!this || !this->layoutLoaded) return; -			char lives [3]; -			sprintf(lives, "%02d", Player_Lives[Player_ID[i]]); -			const char *loaves = lives; -			wchar_t life; +	layout.enableNonLoopAnim(id); +} -			CharToWChar(loaves, &life, 3); +void dWMHud_c::playHideAnim(int id) { +	if (!this || !this->layoutLoaded) return; -			box->SetString(&life); -		} -		else { -			box->alpha = 0; -			pic->alpha = 0; -		} +	if (!layout.isAnimOn(id)) { +		layout.enableNonLoopAnim(id, true);  	} +	layout.grpHandlers[id].frameCtrl.flags = 3; // NO_LOOP | REVERSE +} -	nw4r::lyt::TextBox *coinbox = layout.findTextBoxByName("T_coin_count_01"); - -	char stars [4]; -	int starCoinCount = getStarCoinCount(); -	sprintf(stars, "%03d", starCoinCount); -	const char *scoins = stars; -	wchar_t wcoins; -	CharToWChar(scoins, &wcoins, 4); +void dWMHud_c::loadHeaderInfo() { +	dLevelInfo_c *levelInfo = &dScKoopatlas_c::instance->levelInfo; -	coinbox->SetString(&wcoins); -} +	dLevelInfo_c::entry_s *infEntry = levelInfo->search( +			nodeForHeader->levelNumber[0]-1, nodeForHeader->levelNumber[1]-1); -void dWMHud_c::setLevelText(const char *str, int length) { -	if (str == 0) { -		setLevelText("--NULL STRING--"); +	if (infEntry == 0) { +		LevelName->SetString(L"Unknown Level Name!"); +		LevelNameS->SetString(L"Unknown Level Name!");  		return;  	} -	if (length == -1) { -		length = strlen(str); +	// LEVEL NAME +	wchar_t convertedLevelName[100]; +	const char *sourceLevelName = levelInfo->getNameForLevel(infEntry); +	int charCount = 0; +	 +	while (*sourceLevelName != 0 && charCount < 99) { +		convertedLevelName[charCount] = *sourceLevelName; +		sourceLevelName++; +		charCount++;  	} - -	wchar_t newString[128]; - -	int i; -	for (i = 0; i < length && i < 128; i++) { -		newString[i] = str[i]; +	convertedLevelName[charCount] = 0; + +	LevelName->SetString(convertedLevelName); +	LevelNameS->SetString(convertedLevelName); + +	// LEVEL NUMBER +	wchar_t levelNumber[6]; +	levelNumber[0] = '0' + nodeForHeader->levelNumber[0]; +	levelNumber[1] = '-'; +	if (nodeForHeader->levelNumber[1] >= 10) { +		levelNumber[2] = '0' + (nodeForHeader->levelNumber[1] / 10); +		levelNumber[3] = '0' + (nodeForHeader->levelNumber[1] % 10); +		levelNumber[4] = 0; +	} else { +		levelNumber[2] = '0' + nodeForHeader->levelNumber[1]; +		levelNumber[3] = 0;  	} -	newString[i] = 0; -	setLevelText(newString, i); -} +	LevelNumber->SetString(levelNumber); +	LevelNumberS->SetString(levelNumber); -void dWMHud_c::setLevelText(const wchar_t *str, int length) { -	if (str == 0) { -		setLevelText("--NULL STRING--"); -		return; -	} +	// INFO +	int w = nodeForHeader->levelNumber[0] - 1; +	int l = nodeForHeader->levelNumber[1] - 1; -	if (length == -1) { -		length = wcslen(str); -	} - -	nw4r::lyt::TextBox *box = layout.findTextBoxByName("T_levelname_01"); +	u32 conds = GetSaveFile()->GetBlock(-1)->GetLevelCondition(w, l); +	NormalExitFlag->SetVisible(conds & COND_NORMAL); +	SecretExitFlag->SetVisible(conds & COND_SECRET); +	StarCoinOn[0]->SetVisible(conds & COND_COIN1); +	StarCoinOn[1]->SetVisible(conds & COND_COIN2); +	StarCoinOn[2]->SetVisible(conds & COND_COIN3); +	// SIZE THING  	nw4r::ut::TextWriter tw; -	tw.font = box->font; -	tw.SetFontSize(box->fontSizeX, box->fontSizeY); -	tw.somethingRelatedToLineHeight = box->lineSpace; -	tw.charSpace = box->charSpace; -	if (box->tagProc != 0) -		tw.tagProcessorMaybe = box->tagProc; - -	float width = tw.CalcStringWidth(str, length); -	//SpammyReport("Text width: %f\n", width); - -	layout.findWindowByName("W_levelname")->size.x = width + 22; -	layout.findPictureByName("P_topleftboxbg")->size.x = width; -	layout.findPictureByName("P_topthinboxbg")->size.x = 597 - width; +	tw.font = LevelName->font; +	tw.SetFontSize(LevelName->fontSizeX, LevelName->fontSizeY); +	tw.lineSpace = LevelName->lineSpace; +	tw.charSpace = LevelName->charSpace; +	if (LevelName->tagProc != 0) +		tw.tagProcessor = LevelName->tagProc; + +	float width = tw.CalcStringWidth(convertedLevelName, charCount); +	float totalWidth = width + LevelName->trans.x - 20.0f; +	if (totalWidth < 270.0f) +		totalWidth = 270.0f; +	Header_Centre->size.x = totalWidth; +	Header_Right->trans.x = totalWidth; -	box->SetString(str); +	SaveBlock *save = GetSaveFile()->GetBlock(-1); +	headerCol.colourise(save->hudHintH, save->hudHintS, save->hudHintL);  } -void dWMHud_c::setPointName() { -	// figure this out... -	dKPNode_s *node = dScKoopatlas_c::instance->pathManager.currentNode; - -	if (node->type == dKPNode_s::LEVEL) { -		dLevelInfo_c *li = &dScKoopatlas_c::instance->levelInfo; -		dLevelInfo_c::entry_s *entry = li->search(node->levelNumber[0] - 1, node->levelNumber[1] - 1); +void dWMHud_c::loadFooterInfo() { +	SaveBlock *save = GetSaveFile()->GetBlock(-1); -		setLevelText(li->getNameForLevel(entry)); -	} else { -		setLevelText("   "); -		hidePointBar(); +	wchar_t convertedWorldName[36]; +	int i; +	for (i = 0; i < 36; i++) { +		convertedWorldName[i] = save->newerWorldName[i]; +		if (convertedWorldName[i] == 0) +			break;  	} -} - -void dWMHud_c::checkPointStatus() { -	dKPNode_s *node = dScKoopatlas_c::instance->pathManager.currentNode; - -	if ((node->type == dKPNode_s::LEVEL) && ((node->levelNumber[1] < 30) || (node->levelNumber[1] > 37))) { -		SaveBlock *save = GetSaveFile()->GetBlock(-1); -		 -		int world = node->levelNumber[0]; -		int level = node->levelNumber[1]; - -		u32 conds = save->GetLevelCondition(world-1, level-1); -		nw4r::lyt::Pane *pic; - -		if (conds & COND_COIN1) { -			pic = layout.findPictureByName("P_coin_on_01"); -			pic->alpha = 0xFF; - -			pic = layout.findPictureByName("P_coin_off_01"); -			pic->alpha = 0; -		} -		else { -			pic = layout.findPictureByName("P_coin_on_01"); -			pic->alpha = 0; - -			pic = layout.findPictureByName("P_coin_off_01"); -			pic->alpha = 0xFF; -		} +	convertedWorldName[35] = 0; -		if (conds & COND_COIN2) { -			pic = layout.findPictureByName("P_coin_on_02"); -			pic->alpha = 0xFF; +	WorldName->SetString(convertedWorldName); +	WorldNameS->SetString(convertedWorldName); -			pic = layout.findPictureByName("P_coin_off_02"); -			pic->alpha = 0; -		} -		else { -			pic = layout.findPictureByName("P_coin_on_02"); -			pic->alpha = 0; - -			pic = layout.findPictureByName("P_coin_off_02"); -			pic->alpha = 0xFF; -		} - -		if (conds & COND_COIN3) { -			pic = layout.findPictureByName("P_coin_on_03"); -			pic->alpha = 0xFF; - -			pic = layout.findPictureByName("P_coin_off_03"); -			pic->alpha = 0; -		} -		else { -			pic = layout.findPictureByName("P_coin_on_03"); -			pic->alpha = 0; - -			pic = layout.findPictureByName("P_coin_off_03"); -			pic->alpha = 0xFF; -		} - -		if (conds & COND_NORMAL) { -			pic = layout.findPictureByName("P_normalexitflag"); -			pic->alpha = 0xFF; -		} -		else { -			pic = layout.findPictureByName("P_normalexitflag"); -			pic->alpha = 0; -		} - -		if (conds & COND_SECRET) { -			pic = layout.findPictureByName("P_secretexitflag"); -			pic->alpha = 0xFF; -		} -		else { -			pic = layout.findPictureByName("P_secretexitflag"); -			pic->alpha = 0; -		} +	WorldName->colour1 = save->hudTextColours[0]; +	WorldName->colour2 = save->hudTextColours[1]; -		u8 deaths = save->death_counts[world-1][level-1]; -		nw4r::lyt::TextBox *deathbox = layout.findTextBoxByName("T_death_01"); - -		char die [4]; -		sprintf(die, "%03d", deaths); -		const char *dies = die; -		wchar_t wdie; -		CharToWChar(dies, &wdie, 4); -		deathbox->SetString(&wdie); +	footerCol.colourise(save->hudHintH, save->hudHintS, save->hudHintL); +} -	} else { -		nw4r::lyt::Pane *pic; -		static const char *picNames[8] = {"P_coin_on_01", "P_coin_off_01", "P_coin_on_02", "P_coin_off_02",  -										  "P_coin_on_03", "P_coin_off_03", "P_normalexitflag", "P_secretexitflag"}; -		for (int i = 0; i < 8; i++) { -			pic = layout.findPictureByName(picNames[i]); -			pic->alpha = 0; -		} +void dWMHud_c::enteredNode(dKPNode_s *node) { +	if (node == 0) +		node = dScKoopatlas_c::instance->pathManager.currentNode; -		nw4r::lyt::TextBox *deathbox = layout.findTextBoxByName("T_death_01"); -		wchar_t noDie; -		CharToWChar("---", &noDie, 4); -		deathbox->SetString(&noDie); +	if (node->type == dKPNode_s::LEVEL) { +		willShowHeader = true; +		nodeForHeader = node;  	}  } -void dWMHud_c::setWorldText(const char *str, int length) { -	if (str == 0) { -		setWorldText("--NULL STRING--"); -		return; -	} +void dWMHud_c::leftNode() { +	if (layout.grpHandlers[SHOW_HEADER].frameCtrl.currentFrame > 0.1f) { +		// not hidden -	if (length == -1) { -		length = strlen(str); +		if ((layout.isAnimOn(SHOW_HEADER) && (layout.grpHandlers[SHOW_HEADER].frameCtrl.flags & 2)) +				|| (!layout.isAnimOn(SHOW_HEADER))) { +			// currently being shown, OR fully shown already +			playHideAnim(SHOW_HEADER); +		}  	} +} -	wchar_t newString[128]; -	int i; -	for (i = 0; i < length && i < 128; i++) { -		newString[i] = str[i]; -	} -	newString[i] = 0; - -	setWorldText(newString, i); +void dWMHud_c::hideAndShowFooter() { +	willShowFooter = true; +	playHideAnim(SHOW_FOOTER);  } -void dWMHud_c::setWorldText(const wchar_t *str, int length) { -	if (str == 0) { -		setWorldText("--NULL STRING--"); -		return; -	} - -	if (length == -1) { -		length = wcslen(str); -	} -	nw4r::lyt::TextBox *box = layout.findTextBoxByName("T_area_01"); +void dWMHud_c::setupLives() { +	static const int LogicalPlayerIDs[] = {0,1,3,2}; -	nw4r::ut::TextWriter tw; -	tw.font = box->font; -	tw.SetFontSize(box->fontSizeX, box->fontSizeY); -	tw.somethingRelatedToLineHeight = box->lineSpace; -	tw.charSpace = box->charSpace; -	if (box->tagProc != 0) -		tw.tagProcessorMaybe = box->tagProc; +	P_marioFace_00->SetVisible(false); +	P_luigiFace_00->SetVisible(false); +	P_BkinoFace_00->SetVisible(false); +	P_YkinoFace_00->SetVisible(false); -	float width = tw.CalcStringWidth(str, length); -	//SpammyReport("Text width: %f\n", width); +	int playerCount = 0; -	box->SetString(str); -} +	for (int i = 0; i < 4; i++) { +		// The part in setupLives() +		int playerID = LogicalPlayerIDs[i]; +		int slotID = SearchForIndexOfPlayerID(playerID); +		int lives = Player_Lives[slotID]; +		int length = 2; -void dWMHud_c::setWorldName() { -	// figure this out... -	dKPNode_s *node = dScKoopatlas_c::instance->pathManager.currentNode; +		WriteNumberToTextBox(&lives, &length, T_lifeNumber[slotID], true); -	if (node->type == dKPNode_s::LEVEL) { -		int world = node->levelNumber[0]; -		int level = node->levelNumber[1]; +		// The part in setupIconThings() +		if (QueryPlayerAvailability(slotID)) { +			playerCount++; -		setWorldText(NewerWorldName(NewerWorldForLevelID(world, level))); +			nw4r::lyt::Pane *facePane = (&P_marioFace_00)[playerID]; +			facePane->trans = N_IconPosXP_00[i]->trans; +			facePane->SetVisible(true); +		}  	} -} - -void dWMHud_c::showPointBar() { -	dKPNode_s *node = dScKoopatlas_c::instance->pathManager.currentNode; - -	if (node->type == dKPNode_s::LEVEL) { -		isPointBarShown = true; -		layout.enableNonLoopAnim(ANIM_TOP_SHOW); -	} +	for (int i = 0; i < 4; i++) +		N_IconPosXP_00[i]->SetVisible(false); +	N_IconPosXP_00[playerCount - 1]->SetVisible(true);  } +void dWMHud_c::updatePressableButtonThingies() { +	int cntType = RemoconMng->controllers[0]->controllerType; + +	if (cntType != displayedControllerType) { +		displayedControllerType = cntType; -void dWMHud_c::hidePointBar() { -	if (isPointBarShown) { -		isPointBarShown = false; +		int beef = (cntType == 0) ? 0 : 1; +		GameMgrP->currentControllerType = beef; -		layout.enableNonLoopAnim(ANIM_TOP_HIDE); +		WriteBMGToTextBox( +				layout.findTextBoxByName("ItemsButtonInfo"), +				GetBMG(), 4, 15, 0);  	}  } - diff --git a/src/koopatlas/hud.h b/src/koopatlas/hud.h index 347fcb4..c0079af 100644 --- a/src/koopatlas/hud.h +++ b/src/koopatlas/hud.h @@ -3,6 +3,23 @@  #include "koopatlas/core.h" +// Colourises an IA8 texture +class dTexMapColouriser_c { +	public: +		dTexMapColouriser_c(); +		~dTexMapColouriser_c(); + +		void resetAndClear(); +		void setTexMap(nw4r::lyt::TexMap *tm); +		void applyAlso(nw4r::lyt::TexMap *tm); +		void colourise(int h, int s, int l); + +	private: +		nw4r::lyt::TexMap *texmap; +		u16 *original; +		u16 *mine; +}; +  class dWMHud_c : public dBase_c {  	public:  		dWMHud_c(); @@ -15,25 +32,49 @@ class dWMHud_c : public dBase_c {  		bool layoutLoaded;  		m2d::EmbedLayout_c layout; -		void updateLives(); +		static dWMHud_c *build(); +		static dWMHud_c *instance; -		void showPointBar(); -		void hidePointBar(); +		void enteredNode(dKPNode_s *node = 0); +		void leftNode(); -		void setPointName(); -		void checkPointStatus(); -		void setLevelText(const char *str, int length = -1); -		void setLevelText(const wchar_t *str, int length = -1); +		void hideAndShowFooter(); -		void setWorldName(); -		void setWorldText(const char *str, int length = -1); -		void setWorldText(const wchar_t *str, int length = -1); - -		static dWMHud_c *build(); -		static dWMHud_c *instance; +		void setupLives();  	private: -		bool isPointBarShown; +		void playShowAnim(int id); +		void playHideAnim(int id); +		void loadHeaderInfo(); + +		bool willShowHeader; +		dKPNode_s *nodeForHeader; + +		int displayedControllerType; +		void updatePressableButtonThingies(); + +		void loadFooterInfo(); +		bool willShowFooter; + +		dTexMapColouriser_c headerCol, footerCol; + + +		nw4r::lyt::Pane +			*N_IconPosXP_00[4]; + +		nw4r::lyt::Picture +			*Header_Centre, *Header_Right, *Footer, +			*NormalExitFlag, *SecretExitFlag, +			*StarCoinOn[3], +			*P_marioFace_00, *P_luigiFace_00, +			*P_BkinoFace_00, *P_YkinoFace_00; + +		nw4r::lyt::TextBox +			*LevelName, *LevelNameS, +			*LevelNumber, *LevelNumberS, +			*WorldName, *WorldNameS, +			*StarCoinCounter, +			*T_lifeNumber[4];  };  #endif diff --git a/src/koopatlas/mapdata.cpp b/src/koopatlas/mapdata.cpp index cbd0c69..d766bed 100644 --- a/src/koopatlas/mapdata.cpp +++ b/src/koopatlas/mapdata.cpp @@ -205,6 +205,12 @@ void dKPMapData_c::fixup() {  	fixRef(data->unlockData);  	fixRef(data->sectors);  	fixRef(data->backgroundName); +	if (data->version >= 2) { +		fixRef(data->worlds); +		for (int i = 0; i < data->worldCount; i++) { +			fixRef(data->worlds[i].name); +		} +	}  	for (int iLayer = 0; iLayer < data->layerCount; iLayer++) {  		dKPLayer_s *layer = fixRef(data->layers[iLayer]); @@ -280,6 +286,16 @@ void dKPMapData_c::fixup() {  } +const dKPWorldDef_s *dKPMapData_c::findWorldDef(int id) const { +	for (int i = 0; i < data->worldCount; i++) { +		if (data->worlds[i].key == id) +			return &data->worlds[i]; +	} + +	return 0; +} + +  /******************************************************************************   * Generic Layer   ******************************************************************************/ diff --git a/src/koopatlas/mapdata.h b/src/koopatlas/mapdata.h index bc0c599..f7194ef 100644 --- a/src/koopatlas/mapdata.h +++ b/src/koopatlas/mapdata.h @@ -53,7 +53,7 @@ struct dKPPath_s;  struct dKPNode_s {  	enum NodeTypes { -		PASS_THROUGH, STOP, LEVEL, CHANGE +		PASS_THROUGH, STOP, LEVEL, CHANGE, WORLD_CHANGE  	};  	short x, y; @@ -79,6 +79,7 @@ struct dKPNode_s {  	union {  		struct { u8 levelNumber[2]; bool hasSecret; };  		struct { const char *destMap; u8 thisID, foreignID, transition, _; }; +		struct { u8 worldID, __[3]; };  	};  	dKPPath_s *getAnyExit() { @@ -187,6 +188,15 @@ struct dKPLayer_s {  	int findNodeID(dKPNode_s *node);  }; +struct dKPWorldDef_s { +	const char *name; +	GXColor fsTextColours[2]; +	GXColor fsHintColours[2]; +	GXColor hudTextColours[2]; +	s16 hudHintH, hudHintS, hudHintL; +	u8 key, trackID; +}; +  struct dKPMapFile_s {  	u32 magic;  	int version; @@ -202,6 +212,9 @@ struct dKPMapFile_s {  	dKPLayer_s::sector_s *sectors;  	const char *backgroundName; + +	dKPWorldDef_s *worlds; +	int worldCount;  };  class dKPMapData_c { @@ -253,6 +266,8 @@ class dKPMapData_c {  		dKPNodeExtra_c *levelNodeExtraArray; +		const dKPWorldDef_s *findWorldDef(int id) const; +  		dKPMapData_c();  		bool load(const char *filename);  		~dKPMapData_c(); diff --git a/src/koopatlas/pathmanager.cpp b/src/koopatlas/pathmanager.cpp index 2b85aaa..8a05ea4 100644 --- a/src/koopatlas/pathmanager.cpp +++ b/src/koopatlas/pathmanager.cpp @@ -372,10 +372,12 @@ void dWMPathManager_c::execute() {  void dWMPathManager_c::startMovementTo(dKPPath_s *path) {  	SpammyReport("moving to path %p [%d,%d to %d,%d]\n", path, path->start->x, path->start->y, path->end->x, path->end->y); -	dWMHud_c::instance->hidePointBar(); -	SpammyReport("point bar hidden\n");  	if (!path->isAvailable) { return; } +	if (currentNode && dWMHud_c::instance) +		dWMHud_c::instance->leftNode(); + +	calledEnteredNode = false;  	SpammyReport("a\n");  	isMoving = true; @@ -549,6 +551,18 @@ void dWMPathManager_c::moveThroughPath() {  	player->pos.x += move.x;  	player->pos.y -= move.y; +	// what distance is left? +	if (to->type == dKPNode_s::LEVEL && !calledEnteredNode) { +		Vec toEndVec = {to->x - player->pos.x, to->y + player->pos.y, 0.0f}; +		float distToEnd = VECMag(&toEndVec); +		//OSReport("Distance: %f; To:%d,%d; Player:%f,%f; Diff:%f,%f\n", distToEnd, to->x, to->y, player->pos.x, player->pos.y, toEndVec.x, toEndVec.y); + +		if (distToEnd < 64.0f && dWMHud_c::instance) { +			calledEnteredNode = true; +			dWMHud_c::instance->enteredNode(to); +		} +	} +  	// Check if we've reached the end yet  	if (  			(((move.x > 0) ? (player->pos.x >= to->x) : (player->pos.x <= to->x)) && @@ -564,15 +578,15 @@ void dWMPathManager_c::moveThroughPath() {     		isJumping = false;     		timer = 0.0; -   		SpammyReport("reached path end (%p)\n", to); +   		SpammyReport("reached path end (%p) with type %d\n", to, to->type);     		bool reallyStop = false;     		if (to->type == dKPNode_s::LEVEL) {     			// Always stop on levels     			reallyStop = true; -   		} else if (to->type == dKPNode_s::CHANGE) { -			// Never stop on entrances +   		} else if (to->type == dKPNode_s::CHANGE || to->type == dKPNode_s::WORLD_CHANGE) { +			// Never stop on entrances or on world changes  			reallyStop = false;     		} else if (to->type == dKPNode_s::PASS_THROUGH) {  			// If there's only one exit here, then stop even though @@ -588,6 +602,39 @@ void dWMPathManager_c::moveThroughPath() {  				reallyStop = true;  		} +		if (to->type == dKPNode_s::WORLD_CHANGE) { +			// Set the current world info +			SaveBlock *save = GetSaveFile()->GetBlock(-1); + +			OSReport("Activating world change %d\n", to->worldID); +			const dKPWorldDef_s *world = dScKoopatlas_c::instance->mapData.findWorldDef(to->worldID); +			if (world) { +				if (strncmp(save->newerWorldName, world->name, 36) == 0) { +					OSReport("Already here\n"); +				} else { +					OSReport("Found!\n"); +					strncpy(save->newerWorldName, world->name, 36); +					save->newerWorldName[35] = 0; +					save->currentMapMusic = world->trackID; + +					for (int i = 0; i < 2; i++) { +						save->fsTextColours[i] = world->fsTextColours[i]; +						save->fsHintColours[i] = world->fsHintColours[i]; +						save->hudTextColours[i] = world->hudTextColours[i]; +					} + +					save->hudHintH = world->hudHintH; +					save->hudHintS = world->hudHintS; +					save->hudHintL = world->hudHintL; + +					if (dWMHud_c::instance) +						dWMHud_c::instance->hideAndShowFooter(); +				} +			} else { +				OSReport("Not found!\n"); +			} +		} +  		if (to->type == dKPNode_s::CHANGE) {  			// Go to another map @@ -621,16 +668,8 @@ void dWMPathManager_c::moveThroughPath() {  			SaveBlock *save = GetSaveFile()->GetBlock(-1);  			save->current_path_node = pathLayer->findNodeID(to); - -			if (to->type == dKPNode_s::LEVEL) { -				NWRWorld nWorld = NewerWorldForLevelID(to->levelNumber[0], to->levelNumber[1]); -				if (nWorld != UNKNOWN_WORLD) { -					save->currentNewerWorld = (u8)nWorld; -				} -			} - -			dWMHud_c::instance->showPointBar(); -			SpammyReport("Point bar shown\n"); +			if (!calledEnteredNode && dWMHud_c::instance) +				dWMHud_c::instance->enteredNode();  		} else {  			startMovementTo(to->getOppositeAvailableExitTo(currentPath));  			SpammyReport("passthrough node, continuing to next path\n"); diff --git a/src/koopatlas/pathmanager.h b/src/koopatlas/pathmanager.h index 4604fc7..5579f66 100644 --- a/src/koopatlas/pathmanager.h +++ b/src/koopatlas/pathmanager.h @@ -62,6 +62,8 @@ class dWMPathManager_c {  		bool evaluateUnlockCondition(u8 *&in, SaveBlock *save, int stack);  		bool isEnteringLevel; + +		bool calledEnteredNode;  		int levelStartWait;  		dLevelInfo_c::entry_s *enteredLevel;  }; diff --git a/src/koopatlas/shop.cpp b/src/koopatlas/shop.cpp index 211ab49..cd20ddb 100644 --- a/src/koopatlas/shop.cpp +++ b/src/koopatlas/shop.cpp @@ -1,26 +1,6 @@  #include "koopatlas/shop.h" -int getStarCoinCountShop() { -	SaveBlock *save = GetSaveFile()->GetBlock(-1); -	int coinsSpent = save->credits_hiscore; -	int coinsEarned = 0; - -	for (int w = 0; w < 10; w++) { -		for (int l = 0; l < 10; l++) { -			u32 conds = save->GetLevelCondition(w, l); - -			if (conds & COND_COIN1) { coinsEarned++; } -			if (conds & COND_COIN2) { coinsEarned++; } -			if (conds & COND_COIN3) { coinsEarned++; } -		} -	} - -	int coinsLeft = coinsEarned - coinsSpent; -	return coinsLeft; -} - -  const char* Produce[10][4] = {   	{ "I_kinoko", 		"g3d/I_kinoko.brres", 			"I_kinoko", 			"wait2" },  	{ "I_fireflower", 	"g3d/I_fireflower.brres", 		"I_fireflower", 		"wait2" }, @@ -381,7 +361,7 @@ void dWMShop_c::BuyItem(int item) {  	layout.enableNonLoopAnim(item-1); -	int cash = getStarCoinCountShop(); +	int cash = getStarCoinCount();  	int cost;  	int Powerups[10]; diff --git a/src/koopatlas/starcoin.cpp b/src/koopatlas/starcoin.cpp index 54b7218..3842f87 100644 --- a/src/koopatlas/starcoin.cpp +++ b/src/koopatlas/starcoin.cpp @@ -1,26 +1,6 @@  #include "koopatlas/starcoin.h"  #include <game.h> -int getStarCoinCountCoins() { -	SaveBlock *save = GetSaveFile()->GetBlock(-1); -	int coinsSpent = save->credits_hiscore; -	int coinsEarned = 0; - -	for (int w = 0; w < 10; w++) { -		for (int l = 0; l < 10; l++) { -			u32 conds = save->GetLevelCondition(w, l); - -			if (conds & COND_COIN1) { coinsEarned++; } -			if (conds & COND_COIN2) { coinsEarned++; } -			if (conds & COND_COIN3) { coinsEarned++; } -		} -	} - -	int coinsLeft = coinsEarned - coinsSpent; -	return coinsLeft; -} - -  /*****************************************************************************/  // Starcoin Layout  // @@ -227,7 +207,7 @@ void dWMStarCoin::LoadCoinsForWorld(int world) {  	// Display Total Star Coin Count -	int myCoins = getStarCoinCountCoins(); +	int myCoins = getStarCoinCount();  	char myCoinsStr [4];  	sprintf(myCoinsStr, "%03d", myCoins); @@ -346,10 +326,10 @@ void dWMStarCoin::setText(const char *str, const char *name) {  	nw4r::ut::TextWriter tw;  	tw.font = box->font;  	tw.SetFontSize(box->fontSizeX, box->fontSizeY); -	tw.somethingRelatedToLineHeight = box->lineSpace; +	tw.lineSpace = box->lineSpace;  	tw.charSpace = box->charSpace;  	if (box->tagProc != 0) -		tw.tagProcessorMaybe = box->tagProc; +		tw.tagProcessor = box->tagProc;  	float width = tw.CalcStringWidth(newString, wlength);  	SpammyReport("Text width: %f\n", width);  | 
