# HW03 參考答案 ## 3.1 Bible Credit: 41247039S 韓O劭 (modified) :::spoiler hw0301.c ```c= #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> int32_t inputString(char *str) { if (fgets(str, F_SIZE, stdin) == NULL) { if (fgetc(stdin) == EOF) { printf("myfile: EOF detected\n"); } else { perror("myfile: input error"); } return 1; } if (str[strlen(str) - 1] == '\n') { str[strlen(str) - 1] = '\0'; } return 0; } int32_t openFile(FILE **file, char *fileName, char *mode) { *file = fopen(fileName, mode); if (*file == NULL) { char err[F_SIZE] = {0}; snprintf(err, F_SIZE, "myfile: '%s' error", fileName); perror(err); return 1; } return 0; } void closeFile(FILE *file) { if (file == NULL) { return; } fclose(file); } int32_t searchText(FILE *file, char *search) { if (file == NULL || search == NULL) { printf("mybible: Error input\n"); return 1; } Bible bible = {NULL, 0}; BibleText temp = { 0, 0, {0}, {0} }; while (readBibleText(file, &temp) == 0) { if (hasSearchText(temp.text, search)) { addBibleText(&bible, &temp); } } printBibleText(&bible); freeBible(&bible); return 0; } int32_t readBibleText(FILE *file, BibleText *text) { if (feof(file)) { return 0; } text->chapter = 0; text->verse = 0; text->text[0] = 0; text->id[0] = 0; char format[] = "{\"chapter\":%d,\"verse\":%d,\"text\":\"%[^\"]\",\"translation_id\":\"%*[^\"]\",\"book_id\":\"%[^\"]\",\"book_name\":\"%*[^\"]\"}"; int32_t fs = fscanf(file, format, &(text->chapter), &(text->verse), &(text->text), &(text->id)); if (fs != 4) { return 1; } fgetc(file); return 0; } int32_t addBibleText(Bible *bible, BibleText *text) { int32_t idx = bible->size; bible->size++; if (idx == 0) { bible->text = (BibleText *) calloc(bible->size, sizeof(BibleText)); } else { bible->text = (BibleText *) reallocarray(bible->text, bible->size, sizeof(BibleText)); } bible->text[idx].verse = text->verse; bible->text[idx].chapter = text->chapter; strcpy(bible->text[idx].text, text->text); strcpy(bible->text[idx].id, text->id); return 1; } bool hasSearchText(char *text, char *search) { size_t i = 0; while (i < strlen(text)) { if (!isSameChar(text[i], search[0])) { i++; continue; } size_t k = 0; while (k < strlen(search)) { if (i + k >= strlen(text) || !isSameChar(text[i+k], search[k])) { break; } k++; } if (k == strlen(search)) { return true; } i += k; } return false; } bool isSameChar(char a, char b) { if (a >= 'A' && a <= 'Z') { a += 'a' - 'A'; } if (b >= 'A' && b <= 'Z') { b += 'a' - 'A'; } return (a == b); } void printBibleText(Bible *bible) { printf("Found %d time(s)\n", bible->size); if (bible->size == 0) { return; } for (int32_t i = 0; i < bible->size; i++) { BibleText *tmp = &(bible->text[i]); printf("%d. %s %d:%d %s\n", i+1, tmp->id, tmp->chapter, tmp->verse, tmp->text); } } void freeBible(Bible *bible) { if (bible->size == 0) { return; } free(bible->text); bible->text = NULL; return; } int main() { FILE *file = NULL; char fileName[] = "bible.txt"; char search[F_SIZE] = {0}; if (openFile(&file, fileName, "r")) { return 1; } printf("Please enter the search target: "); if (inputString(search)) { return 1; } if (searchText(file, search)) { printf("Search text error\n"); return 1; } return 0; } ``` ::: ## 3.2 Function Tracer Credit: 41247027S 陳O羽 :::spoiler hw0302.c ```c= #include <stdio.h> #include<stdlib.h> #include<stdint.h> #include<getopt.h> #include<unistd.h> #include<string.h> struct option long_option[] = { {"help",0,NULL,'h'}, {"include",1,NULL,'i'}, {"function",1,NULL,'f'}, {"linum",0,NULL,'l'}, {"code",0,NULL,'c'}, {0,0,0,0} }; typedef struct{ int32_t line; char text[1000]; }FuncPos; int32_t checktype(char *str){ if(strstr(str,"size_t")!=NULL||strstr(str,"void")!=NULL||strstr(str,"int")!=NULL||strstr(str,"short")!=NULL||strstr(str,"long")!=NULL||strstr(str,"float")!=NULL||strstr(str,"double")!=NULL||strstr(str,"char")!=NULL) return 1; else return 0; } int32_t checkchar(char *str){ if((*str == '_'||(*str>='a'&&*str<='z')||(*str>='A'&&*str<='Z')||(*str>='0'&&*str<='9'))) return 1; else return 0; } int32_t FindPositionOfStr(char *str,char word){ for(int32_t i=0;str[i]!='\0';i++){ if(str[i] == word) return i; } } int32_t FindFunc(char *func,FILE* pFile,FuncPos funcPos[]){ int32_t line = 0,cnt=0,anno_status=0; char str[1000]; while(!feof(pFile)){ line++; fgets(str,1000,pFile); char *tmp,*anno; if((anno = strstr(str,"*/"))!=NULL){ if((tmp = strstr(str,func))!=NULL){ if(strlen(tmp)<strlen(anno)){ tmp--; if(!checkchar(tmp)){ tmp += strlen(func) +1; if(!checkchar(tmp)){ funcPos[cnt].line = line; strcpy(funcPos[cnt].text,str); cnt++; } } } } anno_status =0; continue; } if(anno_status==1) continue; if((anno = strstr(str,"//"))!=NULL){ if((tmp = strstr(str,func))!=NULL){ if(strlen(tmp)>strlen(anno)){ tmp--; if(!checkchar(tmp)){ tmp += strlen(func) +1; if(!checkchar(tmp)){ funcPos[cnt].line = line; strcpy(funcPos[cnt].text,str); cnt++; } } } } } else if((anno = strstr(str,"/*"))!=NULL){ if((tmp = strstr(str,func))!=NULL){ if(strlen(tmp)>strlen(anno)){ tmp--; if(!checkchar(tmp)){ tmp += strlen(func) +1; if(!checkchar(tmp)){ funcPos[cnt].line = line; strcpy(funcPos[cnt].text,str); cnt++; } } } } anno_status =1; } else if((tmp = strstr(str,func))!=NULL){ tmp--; if(!checkchar(tmp)){ tmp += strlen(func) +1; if(!checkchar(tmp)){ funcPos[cnt].line = line; strcpy(funcPos[cnt].text,str); cnt++; } } } } return cnt; } int main(int argc, char *argv[]){ int32_t func=0,include=0; for(int i=1;i<argc;i++){ if((strcmp(argv[i],"-f")==0&&strstr(argv[i],"-f")!=NULL)||(strcmp(argv[i],"--function")==0&&strstr(argv[i],"--function")!=NULL)) func = 1; else if((strcmp(argv[i],"-i")==0&&strstr(argv[i],"-i")!=NULL)||(strcmp(argv[i],"--include")==0&&strstr(argv[i],"--include")!=NULL)) include = 1; } if(func&&include){ printf("Wrong input!\n"); return 0; } int32_t option=0,opt_i=0,opt_f=0,opt_h=0,opt_l=0,opt_c=0,index=1; char header[100],function[100]; while((option = getopt_long(argc,argv,"i:f:hlc",long_option,NULL))!=-1){ if(option == 'i'){ opt_i = 1; strcpy(header,optarg); if(!strstr(argv[index],optarg)) index++; if(*(argv[index+1])!='-'){ int32_t check=0; for(int i=index+1;i<argc;i++){ if(*(argv[i])=='-') check=1; } if(check){ printf("Wrong Input!\n"); return 0; } } } else if(option == 'f'){ opt_f = 1; strcpy(function,optarg); if(!strstr(argv[index],optarg)) index++; if(*(argv[index+1])!='-'){ int32_t check=0; for(int i=index+1;i<argc;i++){ if(*(argv[i])=='-') check=1; } if(check){ printf("Wrong Input!\n"); return 0; } } } else if(option == 'h'){ if(*(argv[index+1])!='-'){ int32_t check=0; for(int i=index+1;i<argc;i++){ if(*(argv[i])=='-') check=1; } if(check){ printf("Wrong Input!\n"); return 0; } } opt_h=1; } else if(option == 'l'){ if(*(argv[index+1])!='-'){ int32_t check=0; for(int i=index+1;i<argc;i++){ if(*(argv[i])=='-') check=1; } if(check){ printf("Wrong Input!\n"); return 0; } } opt_l=1; } else if(option == 'c'){ if(*(argv[index+1])!='-'){ int32_t check=0; for(int i=index+1;i<argc;i++){ if(*(argv[i])=='-') check=1; } if(check){ printf("Wrong Input!\n"); return 0; } } opt_c=1; } else if(option == '?'){ printf("Unknown option: %c\n", optopt); return 0; } index++; } if(opt_h){ printf("Usage: hw0302 [options] ... [files] ...\n -f, --function=func Trace the func usage in [Files].\n -i, --include=File Trace all functions listed in the header file in [\n Files].\n -l, --linum Display the line number.\n -c, --code Display the code.\n -h, --help Display this information and exit.\n\n-F and -I are exclusive and must be at least one.\n"); return 0; } else if(opt_f==0&&opt_i==0){ printf("Wrong input!\n"); return 0; } if(opt_f){ printf("%s:\n",function); while(index<argc){ FuncPos funcPos[1000]; int32_t line = 0,cnt=0; char cfile[100]; FILE *cFile; strcpy(cfile,argv[index]); if((cFile = fopen(cfile,"rw"))==NULL){ perror("Could not open the file"); index++; continue; } cnt = FindFunc(function,cFile,funcPos); printf(" %s (count: %d)\n",cfile,cnt); if(opt_l&&opt_c){ for(int32_t i=0;i<cnt;i++) printf(" line %d: %s",funcPos[i].line,funcPos[i].text); } else if(opt_l){ for(int32_t i=0;i<cnt;i++) printf(" line %d\n",funcPos[i].line); } else if(opt_c){ for(int32_t i=0;i<cnt;i++) printf("%s",funcPos[i].text); } index++; fclose(cFile); } } else if(opt_i){ FILE *hFile,*cFile; if((hFile = fopen(header,"rw"))==NULL){ perror("Could not open the file"); return 0; } char cfile[100],str[1000]; while(!feof(hFile)){ FuncPos funcPos[1000]; int32_t cnt =0; fgets(str,1000,hFile); if(checktype(str)){ char *tmp; if((tmp = strstr(str,"("))!=NULL){ while(!checkchar(tmp)) tmp--; int32_t leng=0; while(checkchar(tmp)){ leng++; tmp--; } char *funcName; funcName = calloc(leng+1,sizeof(char)); funcName[leng] = '\0'; tmp++; for(int i=0;i<leng;i++,tmp++) funcName[i] = *tmp; printf("%s:\n",funcName); for(int32_t i=index;i<argc;i++){ strcpy(cfile,argv[i]); if((cFile = fopen(cfile,"rw"))==NULL){ perror("Could not open the file"); continue; } cFile = fopen(cfile,"rw"); cnt = FindFunc(funcName,cFile,funcPos); printf(" %s (count: %d)\n",cfile,cnt); if(opt_l&&opt_c){ for(int32_t i=0;i<cnt;i++) printf(" line %d:%s",funcPos[i].line,funcPos[i].text); } else if(opt_l){ for(int32_t i=0;i<cnt;i++) printf(" line %d\n",funcPos[i].line); } else if(opt_c){ for(int32_t i=0;i<cnt;i++) printf("%s",funcPos[i].text); } fclose(cFile); } } } } } return 0; } ``` ## 3.3 Image Steganography ## 3.4 Game Cheater :::spoiler 41171216H 石O軒 ```c= #include<stdio.h> #include<stdint.h> #include<stdlib.h> #include<string.h> #include<fcntl.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<sys/mman.h> struct Item { uint8_t status; // 狀態值,40=裝備中、00=持有中、80=無物品 uint8_t itemId; // 物品編號 }; //總共有80byte typedef struct _Character { uint8_t XX; // X座標 uint8_t YY; // Y座標 uint8_t Z1; // 人物圖形 uint8_t Z2; // 人物圖形方向 uint8_t Z3; // 人物圖形跑步動作 uint8_t AA; // 動作狀態 uint8_t BB; // 陣營 uint8_t FA; // 肖像編號 uint16_t NN; // 人物姓名,假設名字最長不超過15個字符 struct Item IT[8]; // 物品列表 uint8_t magic[5]; // 法術列表 uint8_t RA; // 種族編號 uint8_t CL; // 職業編號 uint8_t LV; // 等級 uint8_t A_plus; // AP增強狀態 uint8_t D_plus; // DP增強狀態 uint8_t H_plus; // HIT/EV增強狀態 uint8_t sub_H; // 中毒狀態 uint8_t XA; // 麻痺狀態 uint8_t XM; // 封咒狀態 uint8_t space_1[15]; //空15格 uint16_t MT; // 力量 uint16_t DF; // 耐力 uint8_t MV; // 移動力 uint8_t EX; // 經驗值 uint8_t space_2; //空1格 uint16_t DX; // 速度 uint16_t H1; // 目前生命值 uint16_t H2; // 最大生命值 uint16_t M1; // 目前法力值 uint16_t M2; // 最大法力值 uint16_t AP; // 目前總攻擊力 uint16_t DP; // 目前總防禦力 uint16_t HT; // 命中率 uint16_t EV; // 閃避率 }__attribute__ ((__packed__)) character; //印出角色 void print_character(int32_t character_id); //印出道具 int32_t print_item(int32_t item_id); //印出可改數值 void print_change(); //清空螢幕 void clearScreen(){ printf("\033[2J\033[1;1H"); } int main(int argc,char *argv[]){ //如果只有輸入1個 就顯示使用方式 if(argc==1){ printf("Usage: sudo ./hw0304 pid addr\n"); return 0; } //ps aux | grep dosbox 可以抓pid //home/seanshih/hw3/dosgame/fd2 //把pid address存下來 uint64_t address; if(argc==3){ int32_t pid=-1; sscanf(argv[1],"%d",&pid); if(pid==-1){ printf("error: wrong pid.\n"); return 0; } address=strtoull(argv[2],NULL,16); } else{ printf("Usage: sudo ./hw0304 pid addr\n"); return 0; } //先抓檔案名稱 char fileName[1000]={0}; strcpy(fileName,"/proc/"); strcat(fileName,argv[1]); strcat(fileName,"/mem"); //printf("%s\n",fileName); //printf("%ld\n",address); printf("資料讀取中...."); //////重要線索 角色前面int32_t=7685 ///fopen //開啟檔案 FILE *pfile=NULL; if((pfile=fopen(fileName,"rb+"))==NULL){ printf("file is not open!\n"); return 0; } while(1){ //設定檔案大小 uint64_t file_size=16*1024*1024; //創一個角色列表 int32_t character_list[100]; //初始化 for(int32_t i=0;i<100;i++){ character_list[i]=-1; } //有幾個角色 int32_t all_character_size=0; //開始抓位置 uint64_t start; int32_t search_id=7685; int32_t search; FILE *now_pos=pfile; for(uint64_t i=0;i<file_size;i++){ //搜尋到最後了 if(i+79>=file_size){ break; } fseek(now_pos,address+i,SEEK_SET); fread(&search,sizeof(int32_t),1,now_pos); if(search==search_id){ start=i+address+4; //開始把角色抓下來 while(1){ character temp; fread(&temp,sizeof(character),1,now_pos); //printf("(%d,%d)\n",temp.XX,temp.YY); //printf("BB=%d\n",temp.BB); //如果是敵方就不抓角色 if(temp.BB==1 || temp.BB==2){ character_list[all_character_size]=temp.FA; all_character_size++; } else{ break; } } break; } } if(all_character_size==0){ clearScreen(); printf("現在沒有可更改角色!\n"); break; } /////開始改狀態///// char clear; //開始界面 clearScreen(); printf("歡迎來到炎龍騎士團2 修改器!\n"); //選擇角色 int32_t choose_character=-1; int32_t end=0; printf("下面是可選擇的角色:\n"); for(int32_t j=0;j<20;j++){ int32_t check_in_i=0; for(int32_t i=0;i<all_character_size;i++){ if(i*20+j>=all_character_size){ break; } check_in_i=1; printf("%2d.",i*20+j+1); print_character(character_list[i*20+j]); } if(check_in_i==0){ break; } printf("\n"); } printf("請輸入要改的角色編號,如要結束請輸入0: "); scanf("%d",&choose_character); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重新選 if(choose_character<0 || choose_character>all_character_size){ printf("沒有這個角色!\n"); continue; } //如果是0就結束 if(choose_character==0){ break; } //開始改資料 while(1){ //讀取角色資料 //刷新 fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); character now_character; fread(&now_character,sizeof(character),1,now_pos); //printf("(%d,%d)\n",now_character.XX,now_character.YY); int32_t choose_change; //選擇要改什麼資料 printf("下面是可改變的數值:\n"); print_change(); printf("請選擇要改的數值(1-8),如要結束請輸入0,如要重新選擇角色請輸入-1: "); scanf("%d",&choose_change); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重選 if(choose_change<-1 || choose_change>8){ printf("沒有這個選項!\n"); continue; } //如果是0就結束 if(choose_change==0){ end=1; break; } //如果是-1就回上頁 if(choose_change==-1){ clearScreen(); printf("資料讀取中...."); break; } //開始處理資料 //HP if(choose_change==1){ while(1){ int32_t now_HP; printf("請輸入HP要改成多少(0-65535),如要重新選擇數值請輸入-1: "); scanf("%d",&now_HP); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重新輸入 if(now_HP<-1 || now_HP>65535){ printf("超出範圍!\n"); continue; } //如果是-1就回上頁 if(now_HP==-1){ clearScreen(); break; } //改H1 now_character.H1=now_HP; //改H2 now_character.H2=now_HP; fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); fwrite(&now_character,sizeof(character),1,now_pos); printf("已儲存更改!\n"); break; } } //MP if(choose_change==2){ while(1){ int32_t now_MP; printf("請輸入MP要改成多少(0-65535),如要重新選擇數值請輸入-1: "); scanf("%d",&now_MP); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重新輸入 if(now_MP<-1 || now_MP>65535){ printf("超出範圍!\n"); continue; } //如果是-1就回上頁 if(now_MP==-1){ clearScreen(); break; } //改M1 now_character.M1=now_MP; //改M2 now_character.M2=now_MP; fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); fwrite(&now_character,sizeof(character),1,now_pos); printf("已儲存更改!\n"); break; } } //MT if(choose_change==3){ while(1){ int32_t now_MT; printf("請輸入MT要改成多少(0-65535),如要重新選擇數值請輸入-1: "); scanf("%d",&now_MT); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重新輸入 if(now_MT<-1 || now_MT>65535){ printf("超出範圍!\n"); continue; } //如果是-1就回上頁 if(now_MT==-1){ clearScreen(); break; } //改MT now_character.MT=now_MT; fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); fwrite(&now_character,sizeof(character),1,now_pos); printf("已儲存更改!\n"); break; } } //DF if(choose_change==4){ while(1){ int32_t now_DF; printf("請輸入DF要改成多少(0-65535),如要重新選擇數值請輸入-1: "); scanf("%d",&now_DF); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重新輸入 if(now_DF<-1 || now_DF>65535){ printf("超出範圍!\n"); continue; } //如果是-1就回上頁 if(now_DF==-1){ clearScreen(); break; } //改DF now_character.DF=now_DF; fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); fwrite(&now_character,sizeof(character),1,now_pos); printf("已儲存更改!\n"); break; } } //MV if(choose_change==5){ while(1){ int32_t now_MV; printf("請輸入MV要改成多少(0-255)(最好25以內),如要重新選擇數值請輸入-1: "); scanf("%d",&now_MV); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重新輸入 if(now_MV<-1 || now_MV>255){ printf("超出範圍!\n"); continue; } //如果是-1就回上頁 if(now_MV==-1){ clearScreen(); break; } //改MV now_character.MV=now_MV; fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); fwrite(&now_character,sizeof(character),1,now_pos); printf("已儲存更改!\n"); break; } } //EX if(choose_change==6){ while(1){ int32_t now_EX; printf("請輸入EX要改成多少(0-255),如要重新選擇數值請輸入-1: "); scanf("%d",&now_EX); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重新輸入 if(now_EX<-1 || now_EX>255){ printf("超出範圍!\n"); continue; } //如果是-1就回上頁 if(now_EX==-1){ clearScreen(); break; } //改EX now_character.EX=now_EX; fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); fwrite(&now_character,sizeof(character),1,now_pos); printf("已儲存更改!\n"); break; } } //DX if(choose_change==7){ while(1){ int32_t now_DX; printf("請輸入DX要改成多少(0-65535),如要重新選擇數值請輸入-1: "); scanf("%d",&now_DX); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重新輸入 if(now_DX<-1 || now_DX>65535){ printf("超出範圍!\n"); continue; } //如果是-1就回上頁 if(now_DX==-1){ clearScreen(); break; } //改DX now_character.DX=now_DX; fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); fwrite(&now_character,sizeof(character),1,now_pos); printf("已儲存更改!\n"); break; } } //道具 if(choose_change==8){ int32_t change_page=1; while(1){ //秀出道具 //先選道具 printf("第%d頁\n",change_page); for(int32_t j=0;j<15;j++){ int32_t check_in_i=0; for(int32_t i=0;i<60;i++){ if(i*15+j+60*(change_page-1)>=60*change_page){ break; } printf("%3d.",i*15+j+60*(change_page-1)); check_in_i=print_item(i*15+j+60*(change_page-1)); if(check_in_i==0){ printf("\033[0;31m無\033[m "); } } printf("\n"); } int32_t now_item; printf("請輸入要替換的物品編號,上一頁請輸入-3 ,下一頁請輸入-2,如要重新選擇數值請輸入-1: "); scanf("%d",&now_item); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //回上頁 if(now_item==-3){ if(change_page==1){ clearScreen(); printf("沒有上一頁了!\n"); } else{ clearScreen(); change_page--; } continue; } //下一頁 if(now_item==-2){ if(change_page==4){ clearScreen(); printf("沒有下一頁了!\n"); } else{ clearScreen(); change_page++; } continue; } //如果是-1就回上頁 if(now_item==-1){ clearScreen(); break; } //如果輸出錯誤就重新輸入 if((now_item<-3 || now_item>214) || (now_item>=108 && now_item<=122) || (now_item>=125 && now_item<=126) ){ printf("輸入沒有代表物品或指令!\n"); continue; } //要換哪一格 while(1){ int32_t which; printf("你要將\" "); print_item(now_item); printf("\"替換成哪一格呢?\n"); printf("現在背包狀態:\n"); for(int32_t j=0;j<8;j++){ if(now_character.IT[j].status==128){ printf("%d.\033[0;31m無\033[m\n",j+1); } else{ printf("%d.",j+1); print_item(now_character.IT[j].itemId); printf("\n"); } } printf("請輸入要替換的背包位置編號,如要重新選擇物品請輸入-1: "); scanf("%d",&which); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果是-1就回上頁 if(which==-1){ clearScreen(); break; } //如果輸出錯誤就重新輸入 if(which<1 || which>8){ printf("沒有這一格!\n"); continue; } now_character.IT[which-1].status=0; now_character.IT[which-1].itemId=now_item; fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); fwrite(&now_character,sizeof(character),1,now_pos); break; } printf("已儲存更改!\n"); break; } } } if(end==1){ break; } } //結束 printf("再見!\n"); fclose(pfile); return 0; } void print_character(int32_t character_id){ switch(character_id){ case 0: printf("索爾 "); break; case 1: printf("哈諾 "); break; case 2: printf("鐵諾 "); break; case 3: printf("哈瓦特 "); break; case 4: printf("亞雷斯 "); break; case 5: printf("洛娜 "); break; case 6: printf("萊汀 "); break; case 7: printf("蘭斯洛特 "); break; case 8: printf("希莉亞 "); break; case 9: printf("悠妮 "); break; case 10: printf("瑪琳 "); break; case 11: printf("索菲亞 "); break; case 12: printf("凱麗 "); break; case 13: printf("貝克威 "); break; case 14: printf("珊 "); break; case 15: printf("賽可邦勒 "); break; case 16: printf("凱拉斯 "); break; case 17: printf("米亞斯多德 "); break; case 18: printf("蜜蒂 "); break; case 19: printf("羅德曼 "); break; case 20: printf("莎拉 "); break; case 21: printf("約拿 "); break; case 22: printf("卡里斯 "); break; case 23: printf("羅蘭 "); break; case 24: printf("希爾法 "); break; case 25: printf("謝多 "); break; case 26: printf("聖寇拉斯 "); break; case 27: printf("巴拿羅西亞 "); break; case 28: printf("達克賽 "); break; case 29: printf("亞奇梅吉 "); break; case 30: printf("蓋亞 "); break; case 31: printf("渥德 "); break; case 32: printf("索爾(劍聖) "); break; case 33: printf("哈諾(聖戰士) "); break; case 34: printf("鐵諾(劍聖) "); break; case 35: printf("哈瓦特(聖戰士) "); break; case 36: printf("亞雷斯(聖戰士) "); break; case 37: printf("洛娜(聖戰士) "); break; case 38: printf("萊汀(聖戰士) "); break; case 40: printf("希莉亞(狙擊手) "); break; case 41: printf("悠妮(大法師) "); break; case 42: printf("瑪琳(祭司) "); break; case 43: printf("索菲亞(祭司) "); break; case 44: printf("凱麗(鬥士) "); break; case 45: printf("貝克威(狙擊手) "); break; case 46: printf("珊(大法師) "); break; case 47: printf("賽可邦勒(鬥士) "); break; case 49: printf("米亞斯多德(龍劍士)"); break; case 50: printf("索爾(英雄) "); break; case 51: printf("哈諾(魔戰士) "); break; case 52: printf("悠妮(召喚師) "); break; case 53: printf("哈瓦特(魔戰士) "); break; case 54: printf("亞雷斯(龍騎士) "); break; case 55: printf("洛娜(龍騎士) "); break; case 56: printf("萊汀(龍騎士) "); break; case 58: printf("希莉亞(神射手) "); break; case 59: printf("悠妮(聖者) "); break; case 60: printf("瑪琳(聖者) "); break; case 61: printf("索菲亞(聖者) "); break; case 62: printf("凱麗(武聖) "); break; case 63: printf("貝克威(神射手) "); break; case 64: printf("珊(聖者) "); break; case 65: printf("賽可邦勒(武聖) "); break; default: return; } return; } int32_t print_item(int32_t item_id){ switch(item_id){ case 0: printf("短劍 "); return 1; case 1: printf("闊劍 "); return 1; case 2: printf("長劍 "); return 1; case 3: printf("巨劍 "); return 1; case 4: printf("黑暗劍 "); return 1; case 5: printf("戰士劍 "); return 1; case 6: printf("巨魔劍 "); return 1; case 7: printf("斬鐵劍 "); return 1; case 8: printf("流水劍 "); return 1; case 9: printf("大地之劍 "); return 1; case 10: printf("龍神劍 "); return 1; case 11: printf("炎龍劍 "); return 1; case 12: printf("小刀 "); return 1; case 13: printf("匕首 "); return 1; case 14: printf("淬毒刀 "); return 1; case 15: printf("盜賊匕首 "); return 1; case 16: printf("暗殺刀 "); return 1; case 17: printf("護手刀 "); return 1; case 18: printf("忍者刀 "); return 1; case 19: printf("地獄刀 "); return 1; case 20: printf("刺矛 "); return 1; case 21: printf("騎槍 "); return 1; case 22: printf("長戟 "); return 1; case 23: printf("先鋒矛 "); return 1; case 24: printf("斬馬刀 "); return 1; case 25: printf("惡魔之矛 "); return 1; case 26: printf("黃金之戟 "); return 1; case 27: printf("龍之槍 "); return 1; case 28: printf("破魔槍 "); return 1; case 29: printf("戰神戟 "); return 1; case 30: printf("聖之槍 "); return 1; case 31: printf("巨神戟 "); return 1; case 32: printf("手斧 "); return 1; case 33: printf("迴旋斧 "); return 1; case 34: printf("戰斧 "); return 1; case 35: printf("戰鎚 "); return 1; case 36: printf("巨斧 "); return 1; case 37: printf("血之斧 "); return 1; case 38: printf("閃電鎚 "); return 1; case 39: printf("狂暴之斧 "); return 1; case 40: printf("光之斧 "); return 1; case 41: printf("力量之斧 "); return 1; case 42: printf("大地之鎚 "); return 1; case 43: printf("魔神斧 "); return 1; case 44: printf("短弓 "); return 1; case 45: printf("長弓 "); return 1; case 46: printf("黑暗弓 "); return 1; case 47: printf("巨弓 "); return 1; case 48: printf("精靈弓 "); return 1; case 49: printf("狙擊弓 "); return 1; case 50: printf("封魔弓 "); return 1; case 51: printf("風神弓 "); return 1; case 52: printf("長棍 "); return 1; case 53: printf("釘頭鎚 "); return 1; case 54: printf("巨鎚 "); return 1; case 55: printf("槤枷 "); return 1; case 56: printf("魔法杖 "); return 1; case 57: printf("封咒杖 "); return 1; case 58: printf("力之杖 "); return 1; case 59: printf("黑暗杖 "); return 1; case 60: printf("龍之杖 "); return 1; case 61: printf("光之杖 "); return 1; case 62: printf("鐵指套 "); return 1; case 63: printf("鐵爪 "); return 1; case 64: printf("皇帝指環 "); return 1; case 65: printf("毒爪 "); return 1; case 66: printf("殭屍爪 "); return 1; case 67: printf("碎岩爪 "); return 1; case 68: printf("金鋼指環 "); return 1; case 69: printf("裂刃爪 "); return 1; case 70: printf("巨神指環 "); return 1; case 71: printf("魔龍爪 "); return 1; case 72: printf("威力手臂 "); return 1; case 73: printf("金鋼手臂 "); return 1; case 74: printf("雷神手臂 "); return 1; case 75: printf("衝擊手臂 "); return 1; case 76: printf("光束劍 "); return 1; case 77: printf("狙擊槍 "); return 1; case 78: printf("光束槍 "); return 1; case 79: printf("光束砲 "); return 1; case 80: printf("拳頭 "); return 1; case 81: printf("利爪 "); return 1; case 82: printf("觸手 "); return 1; case 83: printf("巨岩手臂 "); return 1; case 84: printf("激水砲 "); return 1; case 85: printf("風牙斬 "); return 1; case 86: printf("魔燄波 "); return 1; case 87: printf("空雷震 "); return 1; case 88: printf("聖者之戒 "); return 1; case 89: printf("勇者徽章 "); return 1; case 90: printf("精靈契印 "); return 1; case 91: printf("領悟之書 "); return 1; case 92: printf("心眼之書 "); return 1; case 93: printf("白金徽章 "); return 1; case 94: printf("生命之實 "); return 1; case 95: printf("魔力水晶 "); return 1; case 96: printf("風精之羽 "); return 1; case 97: printf("十字弓 "); return 1; case 98: printf("水晶弓 "); return 1; case 99: printf("雷神鞭 "); return 1; case 100: printf("天空之鑰 "); return 1; case 101: printf("傳送法杖 "); return 1; case 102: printf("修理套件 "); return 1; case 103: printf("火焰 "); return 1; case 104: printf("火神弓 "); return 1; case 105: printf("鬥神指環 "); return 1; case 106: printf("冰焰 "); return 1; case 107: printf("黑暗波 "); return 1; case 123: printf("巨岩鎧 "); return 1; case 124: printf("魔神甲 "); return 1; case 127: printf("魔岩鎧 "); return 1; case 128: printf("布衣 "); return 1; case 129: printf("旅行裝 "); return 1; case 130: printf("精靈披風 "); return 1; case 131: printf("元素護體 "); return 1; case 132: printf("皮甲 "); return 1; case 133: printf("硬皮甲 "); return 1; case 134: printf("夜行裝 "); return 1; case 135: printf("魔法皮甲 "); return 1; case 136: printf("盜賊之衣 "); return 1; case 137: printf("忍者裝 "); return 1; case 138: printf("潛行服 "); return 1; case 139: printf("神祕裝 "); return 1; case 140: printf("暗殺服 "); return 1; case 141: printf("黑暗之衣 "); return 1; case 142: printf("惡魔皮甲 "); return 1; case 143: printf("雷神服 "); return 1; case 144: printf("環狀甲 "); return 1; case 145: printf("鎖子甲 "); return 1; case 146: printf("鱗甲 "); return 1; case 147: printf("連環鋼甲 "); return 1; case 148: printf("合金鎖甲 "); return 1; case 149: printf("魔法鱗甲 "); return 1; case 150: printf("血環甲 "); return 1; case 151: printf("金鋼鎖甲 "); return 1; case 152: printf("黑暗鱗甲 "); return 1; case 153: printf("力量鎖甲 "); return 1; case 154: printf("惡魔鱗甲 "); return 1; case 155: printf("龍鱗甲 "); return 1; case 156: printf("鎧甲 "); return 1; case 157: printf("銀鎧甲 "); return 1; case 158: printf("魔法鎧甲 "); return 1; case 159: printf("重鎧甲 "); return 1; case 160: printf("地獄鎧甲 "); return 1; case 161: printf("聖鎧甲 "); return 1; case 162: printf("大地鎧甲 "); return 1; case 163: printf("龍神鎧甲 "); return 1; case 164: printf("長袍 "); return 1; case 165: printf("法師袍 "); return 1; case 166: printf("僧侶袍 "); return 1; case 167: printf("祭師袍 "); return 1; case 168: printf("聖者袍 "); return 1; case 169: printf("霧之袍 "); return 1; case 170: printf("黑暗之袍 "); return 1; case 171: printf("天之袍 "); return 1; case 172: printf("武道服 "); return 1; case 173: printf("武鬥裝 "); return 1; case 174: printf("鬥士服 "); return 1; case 175: printf("武者鎧甲 "); return 1; case 176: printf("妖魔鬥服 "); return 1; case 177: printf("武神鬥服 "); return 1; case 178: printf("戰鬥裝甲 "); return 1; case 179: printf("突擊裝甲 "); return 1; case 180: printf("重裝甲 "); return 1; case 181: printf("特殊裝甲 "); return 1; case 182: printf("硬皮 "); return 1; case 183: printf("青色硬皮 "); return 1; case 184: printf("龍鱗 "); return 1; case 185: printf("勒皮 "); return 1; case 186: printf("虛無護甲 "); return 1; case 187: printf("王袍 "); return 1; case 188: printf("鬥士護甲 "); return 1; case 189: printf("地之袍 "); return 1; case 190: printf("水之袍 "); return 1; case 191: printf("大地裝甲 "); return 1; case 192: printf("草藥 "); return 1; case 193: printf("回復劑 "); return 1; case 194: printf("再生藥 "); return 1; case 195: printf("神聖之水 "); return 1; case 196: printf("解毒劑 "); return 1; case 197: printf("退麻藥 "); return 1; case 198: printf("力量藥水 "); return 1; case 199: printf("耐力藥水 "); return 1; case 200: printf("速度藥水 "); return 1; case 201: printf("綠寶石 "); return 1; case 202: printf("紅寶石 "); return 1; case 203: printf("藍寶石 "); return 1; case 204: printf("鑽石 "); return 1; case 205: printf("飛龍卵 "); return 1; case 206: printf("魔法水 "); return 1; case 207: printf("水晶粒 "); return 1; case 208: printf("控制中樞 "); return 1; case 209: printf("黃金徽章 "); return 1; case 210: printf("星之眼 "); return 1; case 211: printf("光之眼 "); return 1; case 212: printf("暗之眼 "); return 1; case 213: printf("冰之眼 "); return 1; case 214: printf("火之眼 "); return 1; default: return 0; } return 0; } //印出可改數值 void print_change(){ printf("1.HP\n"); printf("2.MP\n"); printf("3.MT\n"); printf("4.DF\n"); printf("5.MV\n"); printf("6.EX\n"); printf("7.DX\n"); printf("8.item\n"); return; } ``` ::: ## 3.3 Image Steganography :::spoiler 41171216H 石O軒 ```c= #include<stdio.h> #include<stdint.h> #include<stdlib.h> #include<string.h> #include<getopt.h> #include<sys/types.h> #include<sys/stat.h> #include<sys/mman.h> #include<fcntl.h> #include<unistd.h> struct _BMP_header { char bm[2]; uint32_t size; uint32_t reserve; uint32_t offset; uint32_t header_size; int32_t width; int32_t height; uint16_t planes; uint16_t bpp; uint32_t compression; uint32_t bitmap_size; uint32_t hres; uint32_t vres; uint32_t used; uint32_t important; }__attribute__ ((__packed__)); typedef struct _BMP_header BMP_header; //建立選項列表 struct option long_options[]={ {"write",0,NULL,'w'}, {"extract",0,NULL,'e'}, {"bits",1,NULL,'b'}, {0,0,0,0}, }; //一格像素 typedef struct _pixel{ uint8_t blue; uint8_t green; uint8_t red; }__attribute__ ((__packed__)) pixel; //抓bit int32_t get_bit(uint8_t byte,int32_t n){ return (byte>>n) & 1; } int main(int argc,char *argv[]){ int32_t active_w=0; int32_t active_e=0; int32_t active_b=0; for(int32_t i=0;i<argc;i++){ //擋一開始就輸入檔案 if((strncmp(argv[i],"-",1)!=0) && i==1){ printf("error.\n"); return 0; } //擋中間錯誤輸入 w e if(((strncmp(argv[i],"-w",2)==0)||(strncmp(argv[i],"-e",2)==0)||(strcmp(argv[i],"--write")==0)||(strcmp(argv[i],"--extract")==0)) && (i+2<argc)){ //如果下一個不是 if((strncmp(argv[i+1],"-",1)!=0)){ //如果後面有"-"是錯誤 for(int32_t j=i+2;j<argc;j++){ if((strncmp(argv[j],"-",1)==0)){ printf("error.\n"); return 0; } } } } //擋中間錯誤輸入 b if((strncmp(argv[i],"-b",2)==0) && (i+3<argc)){ //有黏東西 if(strlen(argv[i])>2 && (i+2<argc)){ //如果第2個不是"-" if((strncmp(argv[i+1],"-",1)!=0)){ //如果後面有"-"是錯誤 for(int32_t j=i+2;j<argc;j++){ if((strncmp(argv[j],"-",1)==0)){ printf("error.\n"); return 0; } } } } //沒黏東西 else if(strlen(argv[i])==2 && (i+3<argc)){ //如果第2個不是"-" if((strncmp(argv[i+2],"-",1)!=0)){ //如果後面有"-"是錯誤 for(int32_t j=i+3;j<argc;j++){ if((strncmp(argv[j],"-",1)==0)){ printf("error.\n"); return 0; } } } } } //擋中間錯誤輸入 bits if(strncmp(argv[i],"--bits",6)==0){ //有黏東西 if(strlen(argv[i])>6 && (i+2<argc)){ //如果第2個不是"-" if((strncmp(argv[i+1],"-",1)!=0)){ //如果後面有"-"是錯誤 for(int32_t j=i+2;j<argc;j++){ if((strncmp(argv[j],"-",1)==0)){ printf("error.\n"); return 0; } } } } //沒黏東西 else if(strlen(argv[i])==6 && (i+3<argc)){ //如果第2個不是"-" if((strncmp(argv[i+2],"-",1)!=0)){ //如果後面有"-"是錯誤 for(int32_t j=i+3;j<argc;j++){ if((strncmp(argv[j],"-",1)==0)){ printf("error.\n"); return 0; } } } } } } int32_t now_option=0; int32_t catch_bits=-1; //抓選項 while((now_option=getopt_long(argc,argv,"web:",long_options,NULL))!=-1){ switch(now_option){ case 'w': active_w=1; break; case 'e': active_e=1; break; case 'b': if(strlen(optarg)>1){ printf("error.\n"); return 0; } sscanf(optarg,"%d",&catch_bits); if(catch_bits<1 || catch_bits>8){ printf("error.\n"); return 0; } else{ active_b=1; } break; case '?': printf("error.\n"); return 0; break; default: printf("error.\n"); return 0; break; } } //printf("catch_bits=%d\n",catch_bits); if(active_b==0){ catch_bits=1; } //w和 e不能同時出現 if(active_w==0 && active_e==0){ printf("error.\n"); return 0; } //w和 e不能同時出現 if(active_w==1 && active_e==1){ printf("error: w and e can't appear at the same time.\n"); return 0; } //抓完選項後只能剩下兩個 if(argc-optind<2){ printf("error:no file or no secret data.\n"); return 0; } if(argc-optind>2){ printf("error:unkown data.\n"); return 0; } //抓bmp檔案名稱 char bmp_name[1000]={0}; strcpy(bmp_name,argv[optind]); //printf("%s\n",bmp_name); //檢查副檔名 if(bmp_name[0]==0){ printf("error!\n"); return 0; } char *vicename; if((vicename=strrchr(bmp_name,'.'))==NULL){ printf("error!\n"); return 0; } if(strcmp(vicename,".bmp")!=0){ printf("error!\n"); return 0; } //抓secret data檔案名稱 char secret_data_name[1000]={0}; strcpy(secret_data_name,argv[optind+1]); //開啟bmp檔案 FILE *pfile=NULL; if((pfile=fopen(bmp_name,"rb+"))==NULL){ printf("file is not open!\n"); return 0; } //讀取header BMP_header header; fread(&header,sizeof(header),1,pfile); //檢查magic if(header.bm[0]!='B' || header.bm[1]!='M'){ printf("file is not bmp!\n"); return 0; } //設一個pixel_array pixel pixel_array[header.width * header.height]; fread(pixel_array,sizeof(pixel),header.height * header.width,pfile); uint32_t one_block_size=1; //一區塊大小是2^bits for(int32_t i=0;i<catch_bits;i++){ one_block_size*=2; } ////////////////如果寫入被觸發(-w)//////////////////// if(active_w==1){ //開啟secret data檔案 FILE *secret_pfile=NULL; if((secret_pfile=fopen(secret_data_name,"rb"))==NULL){ printf("file is not open!\n"); return 0; } //抓secret_data的size int32_t fd=0; fd=open(secret_data_name,O_RDONLY); //如果沒開啟檔案 if(fd==-1){ printf("file is not open!\n"); return 0; } struct stat file_stat; fstat(fd,&file_stat); header.reserve=file_stat.st_size; close(fd); //printf("header.reserve=%d\n",header.reserve); //開始抓檔案存進去 uint8_t now_byte; uint8_t now_block=0; uint8_t now_size=0; uint8_t now_color=1; uint64_t now_pixel=0; //做一個用來清零的遮罩 uint32_t mask=255-one_block_size+1; while(feof(secret_pfile)==0){ //檢查如果secret_data到底了 把now_block後面補零直接存入 if(fread(&now_byte,1,1,secret_pfile)!=1){ //printf("now_block%d\n",now_block); //如果剛好存完就跳出 if(now_size==0){ break; } //假如剩下1 擴展到catch bit需要的大小 假如是3 那就變100 else if(now_size>0 && now_size<catch_bits){ //printf("now_block%d\n",now_block); for(int32_t i=0;i<catch_bits-now_size;i++){ now_block*=2; } //printf("now_block%d\n",now_block); //add b if(now_color==1){ //清零指定位數blue pixel_array[now_pixel].blue=pixel_array[now_pixel].blue & mask; //加入數值blue pixel_array[now_pixel].blue+=now_block; } //add g if(now_color==2){ //清零指定位數blue pixel_array[now_pixel].green=pixel_array[now_pixel].green & mask; //加入數值blue pixel_array[now_pixel].green+=now_block; } //add r if(now_color==3){ //清零指定位數blue pixel_array[now_pixel].red=pixel_array[now_pixel].red & mask; //加入數值blue pixel_array[now_pixel].red+=now_block; } } break; } for(int32_t i=7;i>=0;i--){ int32_t now_bit; //抓bit now_bit=get_bit(now_byte,i); now_size++; if(now_size>1){ now_block*=2; } now_block+=now_bit; if(now_size==catch_bits){ //printf("now_block=%d\n",now_block); //檢查now_pixel有沒有到底了 if(now_pixel==((header.width*header.height))){ printf("error: the secret data is larger than the cover BMP’s hiding capacity.\n"); fclose(secret_pfile); fclose(pfile); return 0; } //add b if(now_color==1){ //清零指定位數blue //printf("b_o=%d\n",pixel_array[now_pixel].blue); pixel_array[now_pixel].blue=pixel_array[now_pixel].blue & mask; //printf("now_pixel%d\n",now_pixel); //加入數值blue pixel_array[now_pixel].blue+=now_block; //printf("b=%d\n",pixel_array[now_pixel].blue); } //add g if(now_color==2){ //清零指定位數green //printf("g_o=%d\n",pixel_array[now_pixel].green); pixel_array[now_pixel].green=pixel_array[now_pixel].green & mask; //加入數值green pixel_array[now_pixel].green+=now_block; //printf("g=%d\n",pixel_array[now_pixel].green); } //add r if(now_color==3){ //清零指定位數red //printf("r_o=%d\n",pixel_array[now_pixel].red); pixel_array[now_pixel].red=pixel_array[now_pixel].red & mask; //加入數值red pixel_array[now_pixel].red+=now_block; //printf("r=%d\n",pixel_array[now_pixel].red); } now_size=0; now_block=0; now_color++; if(now_color==4){ now_color=1; now_pixel++; } } } } //開始寫入檔案 fseek(pfile,0,SEEK_SET); fwrite(&header,sizeof(header),1,pfile); fwrite(pixel_array,sizeof(pixel),header.height * header.width,pfile); fclose(secret_pfile); fclose(pfile); } ////////////////如果提取被觸發(-e)//////////////////// if(active_e==1){ if(header.reserve==0){ printf("error: this file don't have secret_data!\n"); return 0; } //開啟secret data檔案 FILE *secret_pfile=NULL; if((secret_pfile=fopen(secret_data_name,"wb"))==NULL){ printf("file is not open!\n"); return 0; } uint8_t now_byte; uint8_t now_block=0; uint8_t now_size=0; uint8_t now_color=1; uint64_t now_pixel=0; uint32_t extract_now_size=0; while(1){ //先抓圖檔裡面的byte //讀取完了 if(now_pixel==(header.width*header.height)){ break; } //從pixel裡面的blue抓 if(now_color==1){ now_byte=pixel_array[now_pixel].blue; } //從pixel裡面的green抓 if(now_color==2){ now_byte=pixel_array[now_pixel].green; } //從pixel裡面的red抓 if(now_color==3){ now_byte=pixel_array[now_pixel].red; } now_color++; if(now_color==4){ now_color=1; now_pixel++; } for(int32_t i=catch_bits-1;i>=0;i--){ int32_t now_bit; //抓bit now_bit=get_bit(now_byte,i); now_size++; if(now_size>1){ now_block*=2; } now_block+=now_bit; //如果抓了8個bit if(now_size==8){ fwrite(&now_block,1,1,secret_pfile); //printf("now_block=%d",now_block); now_size=0; now_block=0; extract_now_size++; } //如果抓完了 if(extract_now_size==header.reserve){ //關閉檔案 fclose(secret_pfile); fclose(pfile); return 0; } } } } } ``` ::: ## 3.4 Game Cheater :::spoiler 41171216H 石O軒 ```c= #include<stdio.h> #include<stdint.h> #include<stdlib.h> #include<string.h> #include<fcntl.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<sys/mman.h> struct Item { uint8_t status; // 狀態值,40=裝備中、00=持有中、80=無物品 uint8_t itemId; // 物品編號 }; //總共有80byte typedef struct _Character { uint8_t XX; // X座標 uint8_t YY; // Y座標 uint8_t Z1; // 人物圖形 uint8_t Z2; // 人物圖形方向 uint8_t Z3; // 人物圖形跑步動作 uint8_t AA; // 動作狀態 uint8_t BB; // 陣營 uint8_t FA; // 肖像編號 uint16_t NN; // 人物姓名,假設名字最長不超過15個字符 struct Item IT[8]; // 物品列表 uint8_t magic[5]; // 法術列表 uint8_t RA; // 種族編號 uint8_t CL; // 職業編號 uint8_t LV; // 等級 uint8_t A_plus; // AP增強狀態 uint8_t D_plus; // DP增強狀態 uint8_t H_plus; // HIT/EV增強狀態 uint8_t sub_H; // 中毒狀態 uint8_t XA; // 麻痺狀態 uint8_t XM; // 封咒狀態 uint8_t space_1[15]; //空15格 uint16_t MT; // 力量 uint16_t DF; // 耐力 uint8_t MV; // 移動力 uint8_t EX; // 經驗值 uint8_t space_2; //空1格 uint16_t DX; // 速度 uint16_t H1; // 目前生命值 uint16_t H2; // 最大生命值 uint16_t M1; // 目前法力值 uint16_t M2; // 最大法力值 uint16_t AP; // 目前總攻擊力 uint16_t DP; // 目前總防禦力 uint16_t HT; // 命中率 uint16_t EV; // 閃避率 }__attribute__ ((__packed__)) character; //印出角色 void print_character(int32_t character_id); //印出道具 int32_t print_item(int32_t item_id); //印出可改數值 void print_change(); //清空螢幕 void clearScreen(){ printf("\033[2J\033[1;1H"); } int main(int argc,char *argv[]){ //如果只有輸入1個 就顯示使用方式 if(argc==1){ printf("Usage: sudo ./hw0304 pid addr\n"); return 0; } //ps aux | grep dosbox 可以抓pid //home/seanshih/hw3/dosgame/fd2 //把pid address存下來 uint64_t address; if(argc==3){ int32_t pid=-1; sscanf(argv[1],"%d",&pid); if(pid==-1){ printf("error: wrong pid.\n"); return 0; } address=strtoull(argv[2],NULL,16); } else{ printf("Usage: sudo ./hw0304 pid addr\n"); return 0; } //先抓檔案名稱 char fileName[1000]={0}; strcpy(fileName,"/proc/"); strcat(fileName,argv[1]); strcat(fileName,"/mem"); //printf("%s\n",fileName); //printf("%ld\n",address); printf("資料讀取中...."); //////重要線索 角色前面int32_t=7685 ///fopen //開啟檔案 FILE *pfile=NULL; if((pfile=fopen(fileName,"rb+"))==NULL){ printf("file is not open!\n"); return 0; } while(1){ //設定檔案大小 uint64_t file_size=16*1024*1024; //創一個角色列表 int32_t character_list[100]; //初始化 for(int32_t i=0;i<100;i++){ character_list[i]=-1; } //有幾個角色 int32_t all_character_size=0; //開始抓位置 uint64_t start; int32_t search_id=7685; int32_t search; FILE *now_pos=pfile; for(uint64_t i=0;i<file_size;i++){ //搜尋到最後了 if(i+79>=file_size){ break; } fseek(now_pos,address+i,SEEK_SET); fread(&search,sizeof(int32_t),1,now_pos); if(search==search_id){ start=i+address+4; //開始把角色抓下來 while(1){ character temp; fread(&temp,sizeof(character),1,now_pos); //printf("(%d,%d)\n",temp.XX,temp.YY); //printf("BB=%d\n",temp.BB); //如果是敵方就不抓角色 if(temp.BB==1 || temp.BB==2){ character_list[all_character_size]=temp.FA; all_character_size++; } else{ break; } } break; } } if(all_character_size==0){ clearScreen(); printf("現在沒有可更改角色!\n"); break; } /////開始改狀態///// char clear; //開始界面 clearScreen(); printf("歡迎來到炎龍騎士團2 修改器!\n"); //選擇角色 int32_t choose_character=-1; int32_t end=0; printf("下面是可選擇的角色:\n"); for(int32_t j=0;j<20;j++){ int32_t check_in_i=0; for(int32_t i=0;i<all_character_size;i++){ if(i*20+j>=all_character_size){ break; } check_in_i=1; printf("%2d.",i*20+j+1); print_character(character_list[i*20+j]); } if(check_in_i==0){ break; } printf("\n"); } printf("請輸入要改的角色編號,如要結束請輸入0: "); scanf("%d",&choose_character); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重新選 if(choose_character<0 || choose_character>all_character_size){ printf("沒有這個角色!\n"); continue; } //如果是0就結束 if(choose_character==0){ break; } //開始改資料 while(1){ //讀取角色資料 //刷新 fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); character now_character; fread(&now_character,sizeof(character),1,now_pos); //printf("(%d,%d)\n",now_character.XX,now_character.YY); int32_t choose_change; //選擇要改什麼資料 printf("下面是可改變的數值:\n"); print_change(); printf("請選擇要改的數值(1-8),如要結束請輸入0,如要重新選擇角色請輸入-1: "); scanf("%d",&choose_change); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重選 if(choose_change<-1 || choose_change>8){ printf("沒有這個選項!\n"); continue; } //如果是0就結束 if(choose_change==0){ end=1; break; } //如果是-1就回上頁 if(choose_change==-1){ clearScreen(); printf("資料讀取中...."); break; } //開始處理資料 //HP if(choose_change==1){ while(1){ int32_t now_HP; printf("請輸入HP要改成多少(0-65535),如要重新選擇數值請輸入-1: "); scanf("%d",&now_HP); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重新輸入 if(now_HP<-1 || now_HP>65535){ printf("超出範圍!\n"); continue; } //如果是-1就回上頁 if(now_HP==-1){ clearScreen(); break; } //改H1 now_character.H1=now_HP; //改H2 now_character.H2=now_HP; fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); fwrite(&now_character,sizeof(character),1,now_pos); printf("已儲存更改!\n"); break; } } //MP if(choose_change==2){ while(1){ int32_t now_MP; printf("請輸入MP要改成多少(0-65535),如要重新選擇數值請輸入-1: "); scanf("%d",&now_MP); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重新輸入 if(now_MP<-1 || now_MP>65535){ printf("超出範圍!\n"); continue; } //如果是-1就回上頁 if(now_MP==-1){ clearScreen(); break; } //改M1 now_character.M1=now_MP; //改M2 now_character.M2=now_MP; fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); fwrite(&now_character,sizeof(character),1,now_pos); printf("已儲存更改!\n"); break; } } //MT if(choose_change==3){ while(1){ int32_t now_MT; printf("請輸入MT要改成多少(0-65535),如要重新選擇數值請輸入-1: "); scanf("%d",&now_MT); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重新輸入 if(now_MT<-1 || now_MT>65535){ printf("超出範圍!\n"); continue; } //如果是-1就回上頁 if(now_MT==-1){ clearScreen(); break; } //改MT now_character.MT=now_MT; fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); fwrite(&now_character,sizeof(character),1,now_pos); printf("已儲存更改!\n"); break; } } //DF if(choose_change==4){ while(1){ int32_t now_DF; printf("請輸入DF要改成多少(0-65535),如要重新選擇數值請輸入-1: "); scanf("%d",&now_DF); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重新輸入 if(now_DF<-1 || now_DF>65535){ printf("超出範圍!\n"); continue; } //如果是-1就回上頁 if(now_DF==-1){ clearScreen(); break; } //改DF now_character.DF=now_DF; fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); fwrite(&now_character,sizeof(character),1,now_pos); printf("已儲存更改!\n"); break; } } //MV if(choose_change==5){ while(1){ int32_t now_MV; printf("請輸入MV要改成多少(0-255)(最好25以內),如要重新選擇數值請輸入-1: "); scanf("%d",&now_MV); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重新輸入 if(now_MV<-1 || now_MV>255){ printf("超出範圍!\n"); continue; } //如果是-1就回上頁 if(now_MV==-1){ clearScreen(); break; } //改MV now_character.MV=now_MV; fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); fwrite(&now_character,sizeof(character),1,now_pos); printf("已儲存更改!\n"); break; } } //EX if(choose_change==6){ while(1){ int32_t now_EX; printf("請輸入EX要改成多少(0-255),如要重新選擇數值請輸入-1: "); scanf("%d",&now_EX); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重新輸入 if(now_EX<-1 || now_EX>255){ printf("超出範圍!\n"); continue; } //如果是-1就回上頁 if(now_EX==-1){ clearScreen(); break; } //改EX now_character.EX=now_EX; fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); fwrite(&now_character,sizeof(character),1,now_pos); printf("已儲存更改!\n"); break; } } //DX if(choose_change==7){ while(1){ int32_t now_DX; printf("請輸入DX要改成多少(0-65535),如要重新選擇數值請輸入-1: "); scanf("%d",&now_DX); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果輸出錯誤就重新輸入 if(now_DX<-1 || now_DX>65535){ printf("超出範圍!\n"); continue; } //如果是-1就回上頁 if(now_DX==-1){ clearScreen(); break; } //改DX now_character.DX=now_DX; fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); fwrite(&now_character,sizeof(character),1,now_pos); printf("已儲存更改!\n"); break; } } //道具 if(choose_change==8){ int32_t change_page=1; while(1){ //秀出道具 //先選道具 printf("第%d頁\n",change_page); for(int32_t j=0;j<15;j++){ int32_t check_in_i=0; for(int32_t i=0;i<60;i++){ if(i*15+j+60*(change_page-1)>=60*change_page){ break; } printf("%3d.",i*15+j+60*(change_page-1)); check_in_i=print_item(i*15+j+60*(change_page-1)); if(check_in_i==0){ printf("\033[0;31m無\033[m "); } } printf("\n"); } int32_t now_item; printf("請輸入要替換的物品編號,上一頁請輸入-3 ,下一頁請輸入-2,如要重新選擇數值請輸入-1: "); scanf("%d",&now_item); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //回上頁 if(now_item==-3){ if(change_page==1){ clearScreen(); printf("沒有上一頁了!\n"); } else{ clearScreen(); change_page--; } continue; } //下一頁 if(now_item==-2){ if(change_page==4){ clearScreen(); printf("沒有下一頁了!\n"); } else{ clearScreen(); change_page++; } continue; } //如果是-1就回上頁 if(now_item==-1){ clearScreen(); break; } //如果輸出錯誤就重新輸入 if((now_item<-3 || now_item>214) || (now_item>=108 && now_item<=122) || (now_item>=125 && now_item<=126) ){ printf("輸入沒有代表物品或指令!\n"); continue; } //要換哪一格 while(1){ int32_t which; printf("你要將\" "); print_item(now_item); printf("\"替換成哪一格呢?\n"); printf("現在背包狀態:\n"); for(int32_t j=0;j<8;j++){ if(now_character.IT[j].status==128){ printf("%d.\033[0;31m無\033[m\n",j+1); } else{ printf("%d.",j+1); print_item(now_character.IT[j].itemId); printf("\n"); } } printf("請輸入要替換的背包位置編號,如要重新選擇物品請輸入-1: "); scanf("%d",&which); //清除緩存區 while((clear=getchar())!='\n' && clear!=EOF); clearScreen(); //如果是-1就回上頁 if(which==-1){ clearScreen(); break; } //如果輸出錯誤就重新輸入 if(which<1 || which>8){ printf("沒有這一格!\n"); continue; } now_character.IT[which-1].status=0; now_character.IT[which-1].itemId=now_item; fseek(now_pos,start+((choose_character-1)*80),SEEK_SET); fwrite(&now_character,sizeof(character),1,now_pos); break; } printf("已儲存更改!\n"); break; } } } if(end==1){ break; } } //結束 printf("再見!\n"); fclose(pfile); return 0; } void print_character(int32_t character_id){ switch(character_id){ case 0: printf("索爾 "); break; case 1: printf("哈諾 "); break; case 2: printf("鐵諾 "); break; case 3: printf("哈瓦特 "); break; case 4: printf("亞雷斯 "); break; case 5: printf("洛娜 "); break; case 6: printf("萊汀 "); break; case 7: printf("蘭斯洛特 "); break; case 8: printf("希莉亞 "); break; case 9: printf("悠妮 "); break; case 10: printf("瑪琳 "); break; case 11: printf("索菲亞 "); break; case 12: printf("凱麗 "); break; case 13: printf("貝克威 "); break; case 14: printf("珊 "); break; case 15: printf("賽可邦勒 "); break; case 16: printf("凱拉斯 "); break; case 17: printf("米亞斯多德 "); break; case 18: printf("蜜蒂 "); break; case 19: printf("羅德曼 "); break; case 20: printf("莎拉 "); break; case 21: printf("約拿 "); break; case 22: printf("卡里斯 "); break; case 23: printf("羅蘭 "); break; case 24: printf("希爾法 "); break; case 25: printf("謝多 "); break; case 26: printf("聖寇拉斯 "); break; case 27: printf("巴拿羅西亞 "); break; case 28: printf("達克賽 "); break; case 29: printf("亞奇梅吉 "); break; case 30: printf("蓋亞 "); break; case 31: printf("渥德 "); break; case 32: printf("索爾(劍聖) "); break; case 33: printf("哈諾(聖戰士) "); break; case 34: printf("鐵諾(劍聖) "); break; case 35: printf("哈瓦特(聖戰士) "); break; case 36: printf("亞雷斯(聖戰士) "); break; case 37: printf("洛娜(聖戰士) "); break; case 38: printf("萊汀(聖戰士) "); break; case 40: printf("希莉亞(狙擊手) "); break; case 41: printf("悠妮(大法師) "); break; case 42: printf("瑪琳(祭司) "); break; case 43: printf("索菲亞(祭司) "); break; case 44: printf("凱麗(鬥士) "); break; case 45: printf("貝克威(狙擊手) "); break; case 46: printf("珊(大法師) "); break; case 47: printf("賽可邦勒(鬥士) "); break; case 49: printf("米亞斯多德(龍劍士)"); break; case 50: printf("索爾(英雄) "); break; case 51: printf("哈諾(魔戰士) "); break; case 52: printf("悠妮(召喚師) "); break; case 53: printf("哈瓦特(魔戰士) "); break; case 54: printf("亞雷斯(龍騎士) "); break; case 55: printf("洛娜(龍騎士) "); break; case 56: printf("萊汀(龍騎士) "); break; case 58: printf("希莉亞(神射手) "); break; case 59: printf("悠妮(聖者) "); break; case 60: printf("瑪琳(聖者) "); break; case 61: printf("索菲亞(聖者) "); break; case 62: printf("凱麗(武聖) "); break; case 63: printf("貝克威(神射手) "); break; case 64: printf("珊(聖者) "); break; case 65: printf("賽可邦勒(武聖) "); break; default: return; } return; } int32_t print_item(int32_t item_id){ switch(item_id){ case 0: printf("短劍 "); return 1; case 1: printf("闊劍 "); return 1; case 2: printf("長劍 "); return 1; case 3: printf("巨劍 "); return 1; case 4: printf("黑暗劍 "); return 1; case 5: printf("戰士劍 "); return 1; case 6: printf("巨魔劍 "); return 1; case 7: printf("斬鐵劍 "); return 1; case 8: printf("流水劍 "); return 1; case 9: printf("大地之劍 "); return 1; case 10: printf("龍神劍 "); return 1; case 11: printf("炎龍劍 "); return 1; case 12: printf("小刀 "); return 1; case 13: printf("匕首 "); return 1; case 14: printf("淬毒刀 "); return 1; case 15: printf("盜賊匕首 "); return 1; case 16: printf("暗殺刀 "); return 1; case 17: printf("護手刀 "); return 1; case 18: printf("忍者刀 "); return 1; case 19: printf("地獄刀 "); return 1; case 20: printf("刺矛 "); return 1; case 21: printf("騎槍 "); return 1; case 22: printf("長戟 "); return 1; case 23: printf("先鋒矛 "); return 1; case 24: printf("斬馬刀 "); return 1; case 25: printf("惡魔之矛 "); return 1; case 26: printf("黃金之戟 "); return 1; case 27: printf("龍之槍 "); return 1; case 28: printf("破魔槍 "); return 1; case 29: printf("戰神戟 "); return 1; case 30: printf("聖之槍 "); return 1; case 31: printf("巨神戟 "); return 1; case 32: printf("手斧 "); return 1; case 33: printf("迴旋斧 "); return 1; case 34: printf("戰斧 "); return 1; case 35: printf("戰鎚 "); return 1; case 36: printf("巨斧 "); return 1; case 37: printf("血之斧 "); return 1; case 38: printf("閃電鎚 "); return 1; case 39: printf("狂暴之斧 "); return 1; case 40: printf("光之斧 "); return 1; case 41: printf("力量之斧 "); return 1; case 42: printf("大地之鎚 "); return 1; case 43: printf("魔神斧 "); return 1; case 44: printf("短弓 "); return 1; case 45: printf("長弓 "); return 1; case 46: printf("黑暗弓 "); return 1; case 47: printf("巨弓 "); return 1; case 48: printf("精靈弓 "); return 1; case 49: printf("狙擊弓 "); return 1; case 50: printf("封魔弓 "); return 1; case 51: printf("風神弓 "); return 1; case 52: printf("長棍 "); return 1; case 53: printf("釘頭鎚 "); return 1; case 54: printf("巨鎚 "); return 1; case 55: printf("槤枷 "); return 1; case 56: printf("魔法杖 "); return 1; case 57: printf("封咒杖 "); return 1; case 58: printf("力之杖 "); return 1; case 59: printf("黑暗杖 "); return 1; case 60: printf("龍之杖 "); return 1; case 61: printf("光之杖 "); return 1; case 62: printf("鐵指套 "); return 1; case 63: printf("鐵爪 "); return 1; case 64: printf("皇帝指環 "); return 1; case 65: printf("毒爪 "); return 1; case 66: printf("殭屍爪 "); return 1; case 67: printf("碎岩爪 "); return 1; case 68: printf("金鋼指環 "); return 1; case 69: printf("裂刃爪 "); return 1; case 70: printf("巨神指環 "); return 1; case 71: printf("魔龍爪 "); return 1; case 72: printf("威力手臂 "); return 1; case 73: printf("金鋼手臂 "); return 1; case 74: printf("雷神手臂 "); return 1; case 75: printf("衝擊手臂 "); return 1; case 76: printf("光束劍 "); return 1; case 77: printf("狙擊槍 "); return 1; case 78: printf("光束槍 "); return 1; case 79: printf("光束砲 "); return 1; case 80: printf("拳頭 "); return 1; case 81: printf("利爪 "); return 1; case 82: printf("觸手 "); return 1; case 83: printf("巨岩手臂 "); return 1; case 84: printf("激水砲 "); return 1; case 85: printf("風牙斬 "); return 1; case 86: printf("魔燄波 "); return 1; case 87: printf("空雷震 "); return 1; case 88: printf("聖者之戒 "); return 1; case 89: printf("勇者徽章 "); return 1; case 90: printf("精靈契印 "); return 1; case 91: printf("領悟之書 "); return 1; case 92: printf("心眼之書 "); return 1; case 93: printf("白金徽章 "); return 1; case 94: printf("生命之實 "); return 1; case 95: printf("魔力水晶 "); return 1; case 96: printf("風精之羽 "); return 1; case 97: printf("十字弓 "); return 1; case 98: printf("水晶弓 "); return 1; case 99: printf("雷神鞭 "); return 1; case 100: printf("天空之鑰 "); return 1; case 101: printf("傳送法杖 "); return 1; case 102: printf("修理套件 "); return 1; case 103: printf("火焰 "); return 1; case 104: printf("火神弓 "); return 1; case 105: printf("鬥神指環 "); return 1; case 106: printf("冰焰 "); return 1; case 107: printf("黑暗波 "); return 1; case 123: printf("巨岩鎧 "); return 1; case 124: printf("魔神甲 "); return 1; case 127: printf("魔岩鎧 "); return 1; case 128: printf("布衣 "); return 1; case 129: printf("旅行裝 "); return 1; case 130: printf("精靈披風 "); return 1; case 131: printf("元素護體 "); return 1; case 132: printf("皮甲 "); return 1; case 133: printf("硬皮甲 "); return 1; case 134: printf("夜行裝 "); return 1; case 135: printf("魔法皮甲 "); return 1; case 136: printf("盜賊之衣 "); return 1; case 137: printf("忍者裝 "); return 1; case 138: printf("潛行服 "); return 1; case 139: printf("神祕裝 "); return 1; case 140: printf("暗殺服 "); return 1; case 141: printf("黑暗之衣 "); return 1; case 142: printf("惡魔皮甲 "); return 1; case 143: printf("雷神服 "); return 1; case 144: printf("環狀甲 "); return 1; case 145: printf("鎖子甲 "); return 1; case 146: printf("鱗甲 "); return 1; case 147: printf("連環鋼甲 "); return 1; case 148: printf("合金鎖甲 "); return 1; case 149: printf("魔法鱗甲 "); return 1; case 150: printf("血環甲 "); return 1; case 151: printf("金鋼鎖甲 "); return 1; case 152: printf("黑暗鱗甲 "); return 1; case 153: printf("力量鎖甲 "); return 1; case 154: printf("惡魔鱗甲 "); return 1; case 155: printf("龍鱗甲 "); return 1; case 156: printf("鎧甲 "); return 1; case 157: printf("銀鎧甲 "); return 1; case 158: printf("魔法鎧甲 "); return 1; case 159: printf("重鎧甲 "); return 1; case 160: printf("地獄鎧甲 "); return 1; case 161: printf("聖鎧甲 "); return 1; case 162: printf("大地鎧甲 "); return 1; case 163: printf("龍神鎧甲 "); return 1; case 164: printf("長袍 "); return 1; case 165: printf("法師袍 "); return 1; case 166: printf("僧侶袍 "); return 1; case 167: printf("祭師袍 "); return 1; case 168: printf("聖者袍 "); return 1; case 169: printf("霧之袍 "); return 1; case 170: printf("黑暗之袍 "); return 1; case 171: printf("天之袍 "); return 1; case 172: printf("武道服 "); return 1; case 173: printf("武鬥裝 "); return 1; case 174: printf("鬥士服 "); return 1; case 175: printf("武者鎧甲 "); return 1; case 176: printf("妖魔鬥服 "); return 1; case 177: printf("武神鬥服 "); return 1; case 178: printf("戰鬥裝甲 "); return 1; case 179: printf("突擊裝甲 "); return 1; case 180: printf("重裝甲 "); return 1; case 181: printf("特殊裝甲 "); return 1; case 182: printf("硬皮 "); return 1; case 183: printf("青色硬皮 "); return 1; case 184: printf("龍鱗 "); return 1; case 185: printf("勒皮 "); return 1; case 186: printf("虛無護甲 "); return 1; case 187: printf("王袍 "); return 1; case 188: printf("鬥士護甲 "); return 1; case 189: printf("地之袍 "); return 1; case 190: printf("水之袍 "); return 1; case 191: printf("大地裝甲 "); return 1; case 192: printf("草藥 "); return 1; case 193: printf("回復劑 "); return 1; case 194: printf("再生藥 "); return 1; case 195: printf("神聖之水 "); return 1; case 196: printf("解毒劑 "); return 1; case 197: printf("退麻藥 "); return 1; case 198: printf("力量藥水 "); return 1; case 199: printf("耐力藥水 "); return 1; case 200: printf("速度藥水 "); return 1; case 201: printf("綠寶石 "); return 1; case 202: printf("紅寶石 "); return 1; case 203: printf("藍寶石 "); return 1; case 204: printf("鑽石 "); return 1; case 205: printf("飛龍卵 "); return 1; case 206: printf("魔法水 "); return 1; case 207: printf("水晶粒 "); return 1; case 208: printf("控制中樞 "); return 1; case 209: printf("黃金徽章 "); return 1; case 210: printf("星之眼 "); return 1; case 211: printf("光之眼 "); return 1; case 212: printf("暗之眼 "); return 1; case 213: printf("冰之眼 "); return 1; case 214: printf("火之眼 "); return 1; default: return 0; } return 0; } //印出可改數值 void print_change(){ printf("1.HP\n"); printf("2.MP\n"); printf("3.MT\n"); printf("4.DF\n"); printf("5.MV\n"); printf("6.EX\n"); printf("7.DX\n"); printf("8.item\n"); return; } ``` ::: ## 3.5 RGB Line Chart :::spoiler 41247027S 陳O羽 ```c #include <stdio.h> #include<stdlib.h> #include<stdint.h> #include<getopt.h> #include<unistd.h> #include<string.h> struct option long_option[] = { {"input",1,NULL,'i'}, {"output",1,NULL,'o'}, {"width",1,NULL,'w'}, {"height",1,NULL,'h'}, {"line",0,NULL,'l'}, {"help",0,NULL,'H'}, {0,0,0,0} }; struct _sBmpHeader { char bm[2]; uint32_t size; uint32_t reserve; uint32_t offset; uint32_t header_size; uint32_t width; uint32_t height; uint16_t planes; uint16_t bpp; uint32_t compression; uint32_t bitmap_size; uint32_t hres; uint32_t vres; uint32_t used; uint32_t important; }__attribute__ ((__packed__)); typedef struct _sBmpHeader sBmpHeader; void draw(int32_t position,int32_t radius,int32_t width,uint8_t *bmp_map,uint32_t maxi){ double color = 255.0/radius; for(int32_t i=radius-1;i>=0;i--){ for(int32_t j=0;j<=i;j++){ if(position+3*j+width*(radius-1-i)<maxi&&position+3*j+width*(radius-1-i)>=0){ if(*(bmp_map+position+3*j+width*(radius-1-i))<color*(i+1-j)) *(bmp_map+position+3*j+width*(radius-1-i)) = color*(i+1-j); } if(position-3*j+width*(radius-1-i)<maxi&&position-3*j+width*(radius-1-i)>=0){ if(*(bmp_map+position-3*j+width*(radius-1-i))<color*(i+1-j)) *(bmp_map+position-3*j+width*(radius-1-i)) = color*(i+1-j); } if(position+3*j-width*(radius-1-i)<maxi&&position+3*j-width*(radius-1-i)>=0){ if(*(bmp_map+position+3*j-width*(radius-1-i))<color*(i+1-j)) *(bmp_map+position+3*j-width*(radius-1-i)) = color*(i+1-j); } if(position-3*j-width*(radius-1-i)<maxi&&position-3*j-width*(radius-1-i)>=0){ if(*(bmp_map+position-3*j-width*(radius-1-i))<color*(i+1-j)) *(bmp_map+position-3*j-width*(radius-1-i)) = color*(i+1-j); } } } } int main(int argc, char *argv[]){ int32_t width,height,radius,option=0,opt_h=0,check=0; char input[100],output[100]; while((option = getopt_long(argc,argv,"i:o:w:h:l:H",long_option,NULL))!=-1){ if(option == 'i'){ check++; strcpy(input,optarg); } else if(option == 'o'){ check++; strcpy(output,optarg); } else if(option == 'w'){ check++; width = atoi(optarg); } else if(option == 'h'){ check++; height = atoi(optarg); } else if(option == 'l'){ check++; radius = atoi(optarg); } else if(option == 'H'){ opt_h = 1; } } if(opt_h){ printf("Usage: hw0302 [options]\n -i, --input, mandatory: input file path\n -o, --output, mandatory: output file path\n -w, --width, mandatory: output bmp file width\n -h, --height, mandatory: output bmp file height\n -l, --line, mandatory: the radius of line\n -H, --help, option: show help message\n"); return 0; } if(check!=5){ printf("Wrong input!\n"); return 0; } FILE *IFile,*OFile; if((IFile = fopen(input,"rb"))==NULL){ printf("Can't Not Open\n"); return 0; } if((OFile = fopen(output,"wb"))==NULL){ printf("Can't Not Open\n"); return 0; } sBmpHeader input_header,output_header; fread(&input_header,sizeof(input_header),1,IFile); uint64_t Blue[256]={0},Red[256]={0},Green[256]={0},maxi=0; int32_t bytes_per_pixel = input_header.bpp / 8; // 每个像素占用的字节数 int32_t alignment_bytes = (4 - ((input_header.width * bytes_per_pixel) % 4)) % 4; // 行字节数对齐所需的填充字节数 fseek(IFile,input_header.offset,SEEK_SET); for (int32_t i = 0; i < input_header.height; i++) { for (int32_t j = 0; j < input_header.width; j++) { for (int32_t k = 0; k < 3; k++) { uint8_t num; fread(&num, sizeof(uint8_t), 1, IFile); // 根据颜色分量的顺序来选择对应的数组递增 if (k == 0) { Blue[num]++; if (Blue[num] > maxi) maxi = Blue[num]; } else if (k == 1) { Green[num]++; if (Green[num] > maxi) maxi = Green[num]; } else if (k == 2) { Red[num]++; if (Red[num] > maxi) maxi = Red[num]; } } } fseek(IFile, alignment_bytes, SEEK_CUR); } int tmp2 = (width*3)%4; if(tmp2>0) tmp2 = 4 - tmp2; strcpy(output_header.bm,"BM"); output_header.offset = 54; output_header.header_size = 40; output_header.reserve = 0; output_header.bpp = 24; output_header.width= width; output_header.height = height; output_header.planes=1; output_header.important = 0; output_header.bitmap_size = width * height * 3 + height * tmp2; output_header.size = output_header.bitmap_size + output_header.offset; output_header.compression = 0; output_header.hres =0; output_header.vres =0; output_header.important=0; output_header.used = 0; fwrite(&output_header,sizeof(output_header),1,OFile); uint8_t *bmp_map; bmp_map =calloc(output_header.bitmap_size,sizeof(uint8_t)); memset(bmp_map,0,output_header.bitmap_size); double vertical = (double)height/(double)maxi,horizontal = (double)width/255.0; //Blue for(int32_t i=1;i<256;i++){ if(Blue[i-1]>=Blue[i]){ double slope = (double)(vertical*(Blue[i-1]-Blue[i]))/(double)(horizontal);//((int32_t)((i)*horizontal)-(int32_t)((i-1)*horizontal)); (int32_t)(vertical*Blue[i-1])-(int32_t)(vertical*Blue[i]) int32_t cnt_height=0; for(int32_t j=0;j<=(horizontal);j++){ if((int32_t)j*slope-cnt_height==0){ draw((int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Blue[i-1]-cnt_height))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size); } else{ for(int32_t k =0;k<=(int32_t)j*slope-cnt_height;k++){ draw((int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Blue[i-1]-(cnt_height+k)))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size); } } cnt_height=j*slope; } } else if(Blue[i-1]<Blue[i]){ double slope = (double)(vertical*(Blue[i]-Blue[i-1]))/(horizontal); int32_t cnt_height=0; for(int32_t j=0;j<=(horizontal);j++){ if((int32_t)j*slope-cnt_height==0){ draw((int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Blue[i-1]+cnt_height))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size); } else{ for(int32_t k =0;k<=(int32_t)j*slope-cnt_height;k++){ draw((int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Blue[i-1]+cnt_height+k))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size); } } cnt_height=j*slope; } } } //Green for(int32_t i=1;i<256;i++){ if(Green[i-1]>=Green[i]){ double slope = (double)(vertical*(Green[i-1]-Green[i]))/(double)(horizontal); int32_t cnt_height=0; for(int32_t j=0;j<=(horizontal);j++){ if((int32_t)j*slope-cnt_height==0){ draw(1+(int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Green[i-1]-cnt_height))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size); } else{ for(int32_t k =0;k<=(int32_t)j*slope-cnt_height;k++){ draw(1+(int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Green[i-1]-(cnt_height+k)))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size); } } cnt_height=j*slope; } } else if(Green[i-1]<Green[i]){ double slope = (double)(vertical*(Green[i]-Green[i-1]))/(horizontal); int32_t cnt_height=0; for(int32_t j=0;j<=(horizontal);j++){ if((int32_t)j*slope-cnt_height==0){ draw(1+(int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Green[i-1]+cnt_height))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size); } else{ for(int32_t k =0;k<=(int32_t)j*slope-cnt_height;k++){ draw(1+(int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Green[i-1]+cnt_height+k))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size); } } cnt_height=j*slope; } } } //Red for(int32_t i=1;i<256;i++){ if(Red[i-1]>=Red[i]){ double slope = (double)(vertical*(Red[i-1]-Red[i]))/(double)(horizontal);//((int32_t)((i)*horizontal)-(int32_t)((i-1)*horizontal)); (int32_t)(vertical*Blue[i-1])-(int32_t)(vertical*Blue[i]) int32_t cnt_height=0; for(int32_t j=0;j<=(horizontal);j++){ if((int32_t)j*slope-cnt_height==0){ draw(2+(int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Red[i-1]-cnt_height))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size); } else{ for(int32_t k =0;k<=(int32_t)j*slope-cnt_height;k++){ draw(2+(int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Red[i-1]-(cnt_height+k)))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size); } } cnt_height=j*slope; } } else if(Red[i-1]<Red[i]){ double slope = (double)(vertical*(Red[i]-Red[i-1]))/(horizontal); int32_t cnt_height=0; for(int32_t j=0;j<=(horizontal);j++){ if((int32_t)j*slope-cnt_height==0){ draw(2+(int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Red[i-1]+cnt_height))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size); } else{ for(int32_t k =0;k<=(int32_t)j*slope-cnt_height;k++){ draw(2+(int32_t)(horizontal*(i-1)+j)*3+((tmp2+width*3)*((int32_t)(vertical*Red[i-1]+cnt_height+k))),radius,tmp2+width*3,bmp_map,output_header.bitmap_size); } } cnt_height=j*slope; } } } fwrite(bmp_map,sizeof(uint8_t),output_header.bitmap_size,OFile); fclose(IFile); fclose(OFile); return 0; } ``` ::: ## 3.6 Bonus: ncurses 不提供範例解答,但可以看看其他人是如何把相關內容寫成部落格的: https://shengyu7697.github.io/cpp-ncurses/